aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc38
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.h11
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc40
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc1009
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h35
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc31
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc223
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h125
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc41
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc681
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h16
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc336
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h61
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc220
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h64
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc7
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc46
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto4
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc15
25 files changed, 1815 insertions, 1209 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 3b4b97e6..8adee0f5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -197,6 +197,8 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
vars["nested_name"] = descriptor_->name();
vars["classname"] = classname_;
vars["constexpr"] = options_.proto_h ? "constexpr " : "";
+ vars["{"] = "";
+ vars["}"] = "";
printer->Print(vars, "typedef $classname$ $nested_name$;\n");
for (int j = 0; j < descriptor_->value_count(); j++) {
@@ -204,22 +206,27 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
"GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
printer->Print(vars,
- "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n"
+ "$deprecated_attr$static $constexpr$const $nested_name$ ${$$tag$$}$ =\n"
" $classname$_$tag$;\n");
+ printer->Annotate("{", "}", descriptor_->value(j));
}
printer->Print(vars,
"static inline bool $nested_name$_IsValid(int value) {\n"
" return $classname$_IsValid(value);\n"
"}\n"
- "static const $nested_name$ $nested_name$_MIN =\n"
- " $classname$_$nested_name$_MIN;\n"
- "static const $nested_name$ $nested_name$_MAX =\n"
+ "static const $nested_name$ ${$$nested_name$_MIN$}$ =\n"
+ " $classname$_$nested_name$_MIN;\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(vars,
+ "static const $nested_name$ ${$$nested_name$_MAX$}$ =\n"
" $classname$_$nested_name$_MAX;\n");
+ printer->Annotate("{", "}", descriptor_);
if (generate_array_size_) {
printer->Print(vars,
- "static const int $nested_name$_ARRAYSIZE =\n"
+ "static const int ${$$nested_name$_ARRAYSIZE$}$ =\n"
" $classname$_$nested_name$_ARRAYSIZE;\n");
+ printer->Annotate("{", "}", descriptor_);
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
@@ -242,27 +249,10 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
}
}
-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,
- "file_level_enum_descriptors[$index_in_metadata$] = "
- "file->enum_type($index$);\n");
- } else {
- vars["parent"] = ClassName(descriptor_->containing_type(), false);
- printer->Print(vars,
- "file_level_enum_descriptors[$index_in_metadata$] = "
- "$parent$_descriptor->enum_type($index$);\n");
- }
-}
-
-void EnumGenerator::GenerateMethods(io::Printer* printer) {
+void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
std::map<string, string> vars;
vars["classname"] = classname_;
- vars["index_in_metadata"] = SimpleItoa(index_in_metadata_);
+ vars["index_in_metadata"] = SimpleItoa(idx);
vars["constexpr"] = options_.proto_h ? "constexpr " : "";
vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 0b568c57..0d2488a9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -86,13 +86,10 @@ class EnumGenerator {
// Source file stuff.
- // Generate code that initializes the global variable storing the enum's
- // descriptor.
- void GenerateDescriptorInitializer(io::Printer* printer);
-
// Generate non-inline methods related to the enum, such as IsValidValue().
- // Goes in the .cc file.
- void GenerateMethods(io::Printer* printer);
+ // Goes in the .cc file. EnumDescriptors are stored in an array, idx is
+ // the index in this array that corresponds with this enum.
+ void GenerateMethods(int idx, io::Printer* printer);
private:
const EnumDescriptor* descriptor_;
@@ -101,8 +98,6 @@ 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 08a635fa..008490ed 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -232,9 +232,8 @@ GenerateSwappingCode(io::Printer* printer) const {
void EnumOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
- printer->Print(
- variables_,
- "_$classname$_default_instance_.$name$_ = $default$;\n");
+ printer->Print(variables_,
+ "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n");
}
// ===================================================================
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 6b1673b2..0a4e0bb9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -167,46 +167,6 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
" $name$($constant_name$, $default$);\n");
}
-void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
- std::map<string, string> vars;
- vars["extendee" ] = ExtendeeClassName(descriptor_);
- vars["number" ] = SimpleItoa(descriptor_->number());
- vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
- vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
- vars["is_packed" ] = (descriptor_->is_repeated() &&
- descriptor_->options().packed())
- ? "true" : "false";
-
- switch (descriptor_->cpp_type()) {
- case FieldDescriptor::CPPTYPE_ENUM:
- printer->Print(
- vars,
- "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n"
- " $extendee$::internal_default_instance(),\n"
- " $number$, $field_type$, $is_repeated$, $is_packed$,\n");
- printer->Print(
- " &$type$_IsValid);\n",
- "type", ClassName(descriptor_->enum_type(), true));
- break;
- case FieldDescriptor::CPPTYPE_MESSAGE:
- printer->Print(
- vars,
- "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
- " $extendee$::internal_default_instance(),\n"
- " $number$, $field_type$, $is_repeated$, $is_packed$,\n");
- printer->Print(" $type$::internal_default_instance());\n", "type",
- ClassName(descriptor_->message_type(), true));
- break;
- default:
- printer->Print(
- vars,
- "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
- " $extendee$::internal_default_instance(),\n"
- " $number$, $field_type$, $is_repeated$, $is_packed$);\n");
- break;
- }
-}
-
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
index 1c1caf1f..30236d71 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -67,9 +67,6 @@ class ExtensionGenerator {
// Source file stuff.
void GenerateDefinition(io::Printer* printer);
- // Generate code to register the extension.
- void GenerateRegistration(io::Printer* printer);
-
private:
const FieldDescriptor* descriptor_;
string type_traits_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index dce9617c..f8e11855 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -61,6 +61,7 @@ using internal::WireFormat;
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
+ (*variables)["ns"] = Namespace(descriptor);
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index a066a6a7..0e74f215 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -55,70 +55,24 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
-namespace {
-// The list of names that are defined as macros on some platforms. We need to
-// #undef them for the generated code to compile.
-const char* kMacroNames[] = {"major", "minor"};
-
-bool IsMacroName(const string& name) {
- // Just do a linear search as the number of elements is very small.
- for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) {
- if (name == kMacroNames[i]) return true;
- }
- return false;
-}
-
-void CollectMacroNames(const Descriptor* message, std::vector<string>* names) {
- for (int i = 0; i < message->field_count(); ++i) {
- const FieldDescriptor* field = message->field(i);
- if (IsMacroName(field->name())) {
- names->push_back(field->name());
- }
- }
- for (int i = 0; i < message->nested_type_count(); ++i) {
- CollectMacroNames(message->nested_type(i), names);
- }
-}
-
-void CollectMacroNames(const FileDescriptor* file, std::vector<string>* names) {
- // Only do this for protobuf's own types. There are some google3 protos using
- // macros as field names and the generated code compiles after the macro
- // expansion. Undefing these macros actually breaks such code.
- if (file->name() != "google/protobuf/compiler/plugin.proto") {
- return;
- }
- for (int i = 0; i < file->message_type_count(); ++i) {
- CollectMacroNames(file->message_type(i), names);
- }
-}
-
-
-} // namespace
-
-// ===================================================================
FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
: file_(file),
options_(options),
scc_analyzer_(options),
- 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_owner_[i].reset(
- new MessageGenerator(file->message_type(i), options, &scc_analyzer_));
- message_generators_owner_[i]->Flatten(&message_generators_);
- }
-
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->AddGenerators(&enum_generators_,
- &extension_generators_);
+ std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file);
+ for (int i = 0; i < msgs.size(); i++) {
+ // Deleted in destructor
+ MessageGenerator* msg_gen =
+ new MessageGenerator(msgs[i], i, options, &scc_analyzer_);
+ message_generators_.push_back(msg_gen);
+ msg_gen->AddGenerators(&enum_generators_, &extension_generators_);
}
for (int i = 0; i < file->enum_type_count(); i++) {
@@ -126,9 +80,6 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
new EnumGenerator(file->enum_type(i), options));
enum_generators_.push_back(enum_generators_owner_[i].get());
}
- for (int i = 0; i < enum_generators_.size(); i++) {
- enum_generators_[i]->index_in_metadata_ = i;
- }
for (int i = 0; i < file->service_count(); i++) {
service_generators_owner_[i].reset(
@@ -147,14 +98,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
extension_generators_.push_back(extension_generators_owner_[i].get());
}
+
package_parts_ = Split(file_->package(), ".", true);
}
-FileGenerator::~FileGenerator() {}
+FileGenerator::~FileGenerator() {
+ for (int i = 0; i < message_generators_.size(); i++) {
+ delete message_generators_[i];
+ }
+}
void FileGenerator::GenerateMacroUndefs(io::Printer* printer) {
+ // Only do this for protobuf's own types. There are some google3 protos using
+ // macros as field names and the generated code compiles after the macro
+ // expansion. Undefing these macros actually breaks such code.
+ if (file_->name() != "google/protobuf/compiler/plugin.proto") {
+ return;
+ }
std::vector<string> names_to_undef;
- CollectMacroNames(file_, &names_to_undef);
+ std::vector<const FieldDescriptor*> fields;
+ ListAllFields(file_, &fields);
+ for (int i = 0; i < fields.size(); i++) {
+ const string& name = fields[i]->name();
+ static const char* kMacroNames[] = {"major", "minor"};
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) {
+ if (name == kMacroNames[i]) {
+ names_to_undef.push_back(name);
+ break;
+ }
+ }
+ }
for (int i = 0; i < names_to_undef.size(); ++i) {
printer->Print(
"#ifdef $name$\n"
@@ -170,43 +143,41 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
GenerateMacroUndefs(printer);
- GenerateForwardDeclarations(printer);
-
- // Open namespace.
- GenerateNamespaceOpeners(printer);
-
GenerateGlobalStateFunctionDeclarations(printer);
- printer->Print("\n");
+ GenerateForwardDeclarations(printer);
- GenerateEnumDefinitions(printer);
+ {
+ NamespaceOpener ns(Namespace(file_), printer);
- printer->Print(kThickSeparator);
- printer->Print("\n");
+ printer->Print("\n");
- GenerateMessageDefinitions(printer);
+ GenerateEnumDefinitions(printer);
- printer->Print("\n");
- printer->Print(kThickSeparator);
- printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
- GenerateServiceDefinitions(printer);
+ GenerateMessageDefinitions(printer);
- GenerateExtensionIdentifiers(printer);
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
- printer->Print("\n");
- printer->Print(kThickSeparator);
- printer->Print("\n");
+ GenerateServiceDefinitions(printer);
- GenerateInlineFunctionDefinitions(printer);
+ GenerateExtensionIdentifiers(printer);
- printer->Print(
- "\n"
- "// @@protoc_insertion_point(namespace_scope)\n"
- "\n");
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+
+ GenerateInlineFunctionDefinitions(printer);
- // Close up namespace.
- GenerateNamespaceClosers(printer);
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n"
+ "\n");
+ }
// We need to specialize some templates in the ::google::protobuf namespace:
GenerateProto2NamespaceEnumSpecializations(printer);
@@ -269,15 +240,12 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer,
// TODO(gerbens) remove this.
printer->Print(
"// @@protoc_insertion_point(includes)\n");
-
- // Open namespace.
- GenerateNamespaceOpeners(printer);
- printer->Print(
- "\n"
- "// @@protoc_insertion_point(namespace_scope)\n");
- // Close up namespace.
- GenerateNamespaceClosers(printer);
-
+ {
+ NamespaceOpener ns(Namespace(file_), printer);
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n");
+ }
printer->Print(
"\n"
"// @@protoc_insertion_point(global_scope)\n"
@@ -287,7 +255,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer,
GenerateBottomHeaderGuard(printer, filename_identifier);
}
-void FileGenerator::GenerateSource(io::Printer* printer) {
+void FileGenerator::GenerateSourceIncludes(io::Printer* printer) {
const bool use_system_include = IsWellKnownMessage(file_);
string header =
StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
@@ -295,9 +263,6 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"// source: $filename$\n"
"\n"
- // The generated code calls accessors that might be deprecated. We don't
- // want the compiler to warn in generated code.
- "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
"#include $left$$header$$right$\n"
"\n"
"#include <algorithm>\n" // for swap()
@@ -340,101 +305,129 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
printer->Print(
"// @@protoc_insertion_point(includes)\n");
+}
+
+void FileGenerator::GenerateSourceDefaultInstance(int idx,
+ io::Printer* printer) {
+ printer->Print(
+ "class $classname$DefaultTypeInternal {\n"
+ " public:\n"
+ " ::google::protobuf::internal::ExplicitlyConstructed<$classname$>\n"
+ " _instance;\n",
+ "classname", message_generators_[idx]->classname_);
+ printer->Indent();
+ message_generators_[idx]->GenerateExtraDefaultFields(printer);
+ printer->Outdent();
+ printer->Print("} _$classname$_default_instance_;\n", "classname",
+ message_generators_[idx]->classname_);
+}
- GenerateNamespaceOpeners(printer);
+namespace {
- for (int i = 0; i < message_generators_.size(); i++) {
- string parent;
- if (IsMapEntryMessage(message_generators_[i]->descriptor_)) {
- parent = ClassName(message_generators_[i]->descriptor_->containing_type(),
- false) +
- "::";
+// Generates weak symbol declarations for types that are to be considered weakly
+// referenced.
+void GenerateWeakDeclarations(
+ const FileDescriptor* file, const Options& options,
+ SCCAnalyzer* scc_analyzer,
+ io::Printer* printer) {
+ std::vector<const FieldDescriptor*> fields;
+ ListAllFields(file, &fields);
+
+ // To ensure determinism and minimize the number of namespace statements,
+ // we output the forward declarations sorted on namespace and type / function
+ // name.
+ std::set<std::pair<string, string> > messages;
+ std::set<std::pair<string, string> > inits;
+ for (int i = 0; i < fields.size(); ++i) {
+ const FieldDescriptor* field = fields[i];
+ bool is_weak = IsImplicitWeakField(field, options);
+ if (is_weak) {
+ const Descriptor* msg = field->message_type();
+ string flns = FileLevelNamespace(msg);
+ string repr = ClassName(scc_analyzer->GetSCC(msg)->GetRepresentative());
+ inits.insert(std::make_pair(flns, "InitDefaults" + repr));
+ inits.insert(std::make_pair(flns, "AddDescriptors"));
+ messages.insert(std::make_pair(Namespace(msg), ClassName(msg)));
}
- printer->Print(
- "class $classname$DefaultTypeInternal {\n"
- "public:\n"
- " ::google::protobuf::internal::ExplicitlyConstructed<$parent$$classname$>\n"
- " _instance;\n",
- "parent", parent, "classname", message_generators_[i]->classname_);
- printer->Indent();
- message_generators_[i]->GenerateExtraDefaultFields(printer);
- printer->Outdent();
- printer->Print(
- "} _$classname$_default_instance_;\n",
- "classname", message_generators_[i]->classname_);
}
- for (int i = 0; i < enum_generators_.size(); i++) {
- enum_generators_[i]->index_in_metadata_ = i;
+ if (messages.empty()) {
+ return;
}
- if (HasGenericServices(file_, options_)) {
- for (int i = 0; i < service_generators_.size(); i++) {
- service_generators_[i]->index_in_metadata_ = i;
- }
+
+ printer->Print("\n");
+ NamespaceOpener ns(printer);
+ for (std::set<std::pair<string, string> >::const_iterator it =
+ messages.begin();
+ it != messages.end(); ++it) {
+ ns.ChangeTo(it->first);
+ printer->Print(
+ "extern __attribute__((weak)) $classname$DefaultTypeInternal "
+ "_$classname$_default_instance_;\n",
+ "classname", it->second);
+ }
+ for (std::set<std::pair<string, string> >::const_iterator it = inits.begin();
+ it != inits.end(); ++it) {
+ ns.ChangeTo(it->first);
+ printer->Print("void $name$() __attribute__((weak));\n",
+ "name", it->second);
}
+}
- printer->Print(
- "\n"
- "namespace $file_namespace$ {\n"
- "\n",
- "file_namespace", FileLevelNamespace(file_->name()));
+} // namespace
- if (HasDescriptorMethods(file_, options_)) {
- printer->Print(
- "\n"
- "namespace {\n"
- "\n");
+void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
+ GenerateSourceIncludes(printer);
+ GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer);
- if (!message_generators_.empty()) {
- printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n",
- "size", SimpleItoa(message_generators_.size()));
- }
- if (!enum_generators_.empty()) {
- printer->Print(
- "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()));
- }
+ { // package namespace
+ NamespaceOpener ns(Namespace(file_), printer);
+
+ // Define default instances
+ GenerateSourceDefaultInstance(idx, printer);
+
+ // Generate classes.
+ printer->Print("\n");
+ message_generators_[idx]->GenerateClassMethods(printer);
printer->Print(
- "\n"
- "} // namespace\n"
- "\n");
- }
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n");
+ } // end package namespace
- // Define our externally-visible BuildDescriptors() function. (For the lite
- // library, all this does is initialize default instances.)
- GenerateBuildDescriptors(printer);
+ if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) {
+ NamespaceOpener ns(FileLevelNamespace(file_), printer);
+ GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer);
+ }
printer->Print(
"\n"
- "} // namespace $file_namespace$\n"
- "\n",
- "file_namespace", FileLevelNamespace(file_->name()));
+ "// @@protoc_insertion_point(global_scope)\n");
+}
+
+void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
+ GenerateSourceIncludes(printer);
+ GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer);
+
+ // TODO(gerbens) Generate tables here
+
+ // Define the code to initialize reflection. This code uses a global
+ // constructor to register reflection data with the runtime pre-main.
+ if (HasDescriptorMethods(file_, options_)) {
+ NamespaceOpener ns(FileLevelNamespace(file_), printer);
+ GenerateReflectionInitializationCode(printer);
+ }
+
+ NamespaceOpener ns(Namespace(file_), printer);
// Generate enums.
for (int i = 0; i < enum_generators_.size(); i++) {
- enum_generators_[i]->GenerateMethods(printer);
+ enum_generators_[i]->GenerateMethods(i, printer);
}
- // Generate classes.
- for (int i = 0; i < message_generators_.size(); i++) {
- printer->Print("\n");
- printer->Print(kThickSeparator);
- printer->Print("\n");
- message_generators_[i]->GenerateClassMethods(printer);
-
- printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n");
- // Generate class inline methods.
- message_generators_[i]->GenerateInlineMethods(printer,
- /* is_inline = */ false);
- printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // Define extensions.
+ for (int i = 0; i < extension_generators_.size(); i++) {
+ extension_generators_[i]->GenerateDefinition(printer);
}
if (HasGenericServices(file_, options_)) {
@@ -446,18 +439,76 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
service_generators_[i]->GenerateImplementation(printer);
}
}
+}
- // Define extensions.
- for (int i = 0; i < extension_generators_.size(); i++) {
- extension_generators_[i]->GenerateDefinition(printer);
+void FileGenerator::GenerateSource(io::Printer* printer) {
+ GenerateSourceIncludes(printer);
+ GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer);
+
+ {
+ NamespaceOpener ns(Namespace(file_), printer);
+
+ // Define default instances
+ for (int i = 0; i < message_generators_.size(); i++) {
+ GenerateSourceDefaultInstance(i, printer);
+ if (UsingImplicitWeakFields(file_, options_)) {
+ printer->Print("void $classname$_Reference() {}\n", "classname",
+ message_generators_[i]->classname_);
+ }
+ }
}
- printer->Print(
- "\n"
- "// @@protoc_insertion_point(namespace_scope)\n");
+ {
+ NamespaceOpener ns(FileLevelNamespace(file_), printer);
+ // Define the initialization code to initialize the default instances.
+ // This code doesn't use a global constructor.
+ GenerateInitializationCode(printer);
- GenerateNamespaceClosers(printer);
+ // Define the code to initialize reflection. This code uses a global
+ // constructor to register reflection data with the runtime pre-main.
+ if (HasDescriptorMethods(file_, options_)) {
+ GenerateReflectionInitializationCode(printer);
+ }
+ }
+
+
+ {
+ NamespaceOpener ns(Namespace(file_), printer);
+
+ // Actually implement the protos
+
+ // Generate enums.
+ for (int i = 0; i < enum_generators_.size(); i++) {
+ enum_generators_[i]->GenerateMethods(i, printer);
+ }
+ // Generate classes.
+ for (int i = 0; i < message_generators_.size(); i++) {
+ printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ message_generators_[i]->GenerateClassMethods(printer);
+ }
+
+ if (HasGenericServices(file_, options_)) {
+ // Generate services.
+ for (int i = 0; i < service_generators_.size(); i++) {
+ if (i == 0) printer->Print("\n");
+ printer->Print(kThickSeparator);
+ printer->Print("\n");
+ service_generators_[i]->GenerateImplementation(printer);
+ }
+ }
+
+ // Define extensions.
+ for (int i = 0; i < extension_generators_.size(); i++) {
+ extension_generators_[i]->GenerateDefinition(printer);
+ }
+
+ printer->Print(
+ "\n"
+ "// @@protoc_insertion_point(namespace_scope)\n");
+ }
printer->Print(
"\n"
"// @@protoc_insertion_point(global_scope)\n");
@@ -512,6 +563,10 @@ class FileGenerator::ForwardDeclarations {
options.dllexport_decl.empty() ? "" : options.dllexport_decl + " ",
"classname",
it->first);
+ if (options.lite_implicit_weak_fields) {
+ printer->Print("void $classname$_Reference();\n",
+ "classname", it->first);
+ }
}
for (std::map<string, ForwardDeclarations *>::const_iterator
it = namespaces_.begin(),
@@ -532,13 +587,11 @@ class FileGenerator::ForwardDeclarations {
std::map<string, const EnumDescriptor*> enums_;
};
-void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
+void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
// AddDescriptors() is a file-level procedure which adds the encoded
// FileDescriptorProto for this .proto file to the global DescriptorPool for
// generated files (DescriptorPool::generated_pool()). It ordinarily runs at
- // static initialization time, but is not used at all in LITE_RUNTIME mode
- // except when extensions are used. This procedure also constructs default
- // instances and registers extensions.
+ // static initialization time, but is not used at all in LITE_RUNTIME mode.
//
// Its sibling, AssignDescriptors(), actually pulls the compiled
// FileDescriptor from the DescriptorPool and uses it to populate all of
@@ -547,172 +600,83 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// anyone calls descriptor() or GetReflection() on one of the types defined
// in the file.
- // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
- // and we only use AddDescriptors() to allocate default instances.
-
- // TODO(ckennelly): Gate this with the same options flag to enable
- // table-driven parsing.
-
- printer->Print("PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n"
- " const TableStruct::entries[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
- printer->Indent();
-
- std::vector<size_t> entries;
- size_t count = 0;
- for (int i = 0; i < message_generators_.size(); i++) {
- size_t value = message_generators_[i]->GenerateParseOffsets(printer);
- entries.push_back(value);
- count += value;
- }
-
- // We need these arrays to exist, and MSVC does not like empty arrays.
- if (count == 0) {
- printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n");
- }
-
- printer->Outdent();
- printer->Print(
- "};\n"
- "\n"
- "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n"
- " const TableStruct::aux[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
- printer->Indent();
-
- std::vector<size_t> aux_entries;
- count = 0;
- for (int i = 0; i < message_generators_.size(); i++) {
- size_t value = message_generators_[i]->GenerateParseAuxTable(printer);
- aux_entries.push_back(value);
- count += value;
- }
-
- if (count == 0) {
- printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ if (!message_generators_.empty()) {
+ printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", "size",
+ SimpleItoa(message_generators_.size()));
}
-
- printer->Outdent();
- printer->Print(
- "};\n"
- "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n"
- " TableStruct::schema[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
- printer->Indent();
-
- size_t offset = 0;
- size_t aux_offset = 0;
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->GenerateParseTable(printer, offset, aux_offset);
- offset += entries[i];
- aux_offset += aux_entries[i];
+ if (!enum_generators_.empty()) {
+ printer->Print(
+ "const ::google::protobuf::EnumDescriptor* "
+ "file_level_enum_descriptors[$size$];\n",
+ "size", SimpleItoa(enum_generators_.size()));
}
-
- if (message_generators_.empty()) {
- printer->Print("{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },\n");
+ 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()));
}
- printer->Outdent();
- printer->Print(
- "};\n"
- "\n");
-
- if (!message_generators_.empty() && options_.table_driven_serialization) {
+ if (!message_generators_.empty()) {
printer->Print(
- "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] "
- "= {\n");
+ "\n"
+ "const ::google::protobuf::uint32 TableStruct::offsets[] "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
- std::vector<int> field_metadata_offsets;
- int idx = 0;
+ std::vector<std::pair<size_t, size_t> > pairs;
+ pairs.reserve(message_generators_.size());
for (int i = 0; i < message_generators_.size(); i++) {
- field_metadata_offsets.push_back(idx);
- idx += message_generators_[i]->GenerateFieldMetadata(printer);
+ pairs.push_back(message_generators_[i]->GenerateOffsets(printer));
}
- field_metadata_offsets.push_back(idx);
printer->Outdent();
printer->Print(
"};\n"
- "const ::google::protobuf::internal::SerializationTable "
- "TableStruct::serialization_table[] = {\n");
+ "static const ::google::protobuf::internal::MigrationSchema schemas[] "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\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"
+ "\nstatic "
+ "::google::protobuf::Message const * const file_default_instances[] = {\n");
printer->Indent();
- // We rely on the order we layout the tables to match the order we
- // calculate them with FlattenMessagesInFile, so we check here that
- // these match exactly.
- std::vector<const Descriptor*> calculated_order =
- FlattenMessagesInFile(file_);
- GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size());
for (int i = 0; i < message_generators_.size(); i++) {
- GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_);
+ const Descriptor* descriptor = message_generators_[i]->descriptor_;
printer->Print(
- "{$num_fields$, TableStruct::field_metadata + $index$},\n",
- "classname", message_generators_[i]->classname_, "num_fields",
- SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]),
- "index", SimpleItoa(field_metadata_offsets[i]));
+ "reinterpret_cast<const "
+ "::google::protobuf::Message*>(&$ns$::_$classname$_default_instance_),\n",
+ "classname", ClassName(descriptor), "ns", Namespace(descriptor));
}
printer->Outdent();
printer->Print(
"};\n"
"\n");
+ } else {
+ // we still need these symbols to exist
+ printer->Print(
+ // MSVC doesn't like empty arrays, so we add a dummy.
+ "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n"
+ "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n"
+ "static const ::google::protobuf::Message* const* "
+ "file_default_instances = NULL;\n"
+ "\n");
}
- if (HasDescriptorMethods(file_, options_)) {
- if (!message_generators_.empty()) {
- printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\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->Print(
- "};\n"
- "static const ::google::protobuf::internal::MigrationSchema schemas[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\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"
- "\nstatic "
- "::google::protobuf::Message const * const file_default_instances[] = {\n");
- printer->Indent();
- for (int i = 0; i < message_generators_.size(); i++) {
- const Descriptor* descriptor = message_generators_[i]->descriptor_;
- printer->Print(
- "reinterpret_cast<const "
- "::google::protobuf::Message*>(&_$classname$_default_instance_),\n",
- "classname", ClassName(descriptor, false));
- }
- printer->Outdent();
- printer->Print(
- "};\n"
- "\n");
- } else {
- // we still need these symbols to exist
- printer->Print(
- // MSVC doesn't like empty arrays, so we add a dummy.
- "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n"
- "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n"
- "static const ::google::protobuf::Message* const* "
- "file_default_instances = NULL;\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";
+ // 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"
"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
@@ -733,20 +697,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
? "file_level_service_descriptors"
: "NULL",
"factory", message_factory);
- // TODO(gerbens) have the compiler include the schemas for map types
- // so that this can go away, and we can potentially use table driven
- // serialization for map types as well.
- for (int i = 0; i < message_generators_.size(); i++) {
- if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) continue;
- printer->Print(
- "file_level_metadata[$index$].reflection = "
- "$parent$::$classname$::CreateReflection(file_level_metadata[$index$]"
- ".descriptor, _$classname$_default_instance_._instance.get_mutable());\n",
- "index", SimpleItoa(i), "parent",
- ClassName(message_generators_[i]->descriptor_->containing_type(),
- false),
- "classname", ClassName(message_generators_[i]->descriptor_, false));
- }
printer->Print(
"}\n"
"\n"
@@ -769,7 +719,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// 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&) "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_COLD;\n"
"void protobuf_RegisterTypes(const ::std::string&) {\n"
" protobuf_AssignDescriptorsOnce();\n");
printer->Indent();
@@ -783,63 +734,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Outdent();
printer->Print(
- "}\n"
- "\n"
- "} // namespace\n");
- }
-
- // Now generate the InitDefaultsImpl() function.
- printer->Print(
- "void TableStruct::InitDefaultsImpl() {\n"
- " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n"
- // Force initialization of primitive values we depend on.
- " ::google::protobuf::internal::InitProtobufDefaults();\n");
-
- printer->Indent();
-
- // Call the InitDefaults() methods for all of our dependencies, to make
- // sure they get added first.
- for (int i = 0; i < file_->dependency_count(); i++) {
- const FileDescriptor* dependency = file_->dependency(i);
- // Print the namespace prefix for the dependency.
- string file_namespace = QualifiedFileLevelSymbol(
- dependency->package(), FileLevelNamespace(dependency->name()));
- // Call its AddDescriptors function.
- printer->Print("$file_namespace$::InitDefaults();\n", "file_namespace",
- file_namespace);
- }
-
- // 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 < message_generators_.size(); i++) {
- message_generators_[i]->GenerateDefaultInstanceAllocator(printer);
- }
- for (int i = 0; i < extension_generators_.size(); i++) {
- extension_generators_[i]->GenerateRegistration(printer);
- }
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
- }
- printer->Outdent();
- printer->Print(
- "}\n"
- "\n"
- "void InitDefaults() {\n"
- " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n"
- " ::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);\n"
- "}\n");
-
- // -----------------------------------------------------------------
+ "}\n"
+ "\n");
- // Now generate the AddDescriptors() function.
- printer->Print(
- "namespace {\n"
- "void AddDescriptorsImpl() {\n"
- " InitDefaults();\n");
+ // Now generate the AddDescriptors() function.
+ printer->Print(
+ "void AddDescriptorsImpl() {\n"
+ " InitDefaults();\n");
+ printer->Indent();
- printer->Indent();
- if (HasDescriptorMethods(file_, options_)) {
// Embed the descriptor. We simply serialize the entire
// FileDescriptorProto
// and embed it as a string literal, which is parsed and built into real
@@ -850,10 +753,11 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
file_proto.SerializeToString(&file_data);
printer->Print("static const char descriptor[] "
- "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) "
+ "= {\n");
printer->Indent();
- if (file_data.size() > 66535) {
+ if (file_data.size() > 65535) {
// 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.
@@ -887,31 +791,27 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
" \"$filename$\", &protobuf_RegisterTypes);\n",
"filename", file_->name());
- }
// Call the AddDescriptors() methods for all of our dependencies, to make
// sure they get added first.
for (int i = 0; i < file_->dependency_count(); i++) {
const FileDescriptor* dependency = file_->dependency(i);
// Print the namespace prefix for the dependency.
- string file_namespace = QualifiedFileLevelSymbol(
- dependency->package(), FileLevelNamespace(dependency->name()));
+ string file_namespace = FileLevelNamespace(dependency);
// Call its AddDescriptors function.
- printer->Print("$file_namespace$::AddDescriptors();\n", "file_namespace",
+ printer->Print("::$file_namespace$::AddDescriptors();\n", "file_namespace",
file_namespace);
}
printer->Outdent();
printer->Print(
"}\n"
- "} // anonymous namespace\n"
"\n"
"void AddDescriptors() {\n"
" static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n"
" ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n"
"}\n");
- if (StaticInitializersForced(file_, options_)) {
printer->Print(
"// Force AddDescriptors() to be called at dynamic initialization "
"time.\n"
@@ -920,24 +820,213 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
" AddDescriptors();\n"
" }\n"
"} static_descriptor_initializer;\n");
- }
}
-void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
- if (package_parts_.size() > 0) printer->Print("\n");
+void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) {
+ const string scc_name = ClassName(scc->GetRepresentative());
+ printer->Print(
+ "void InitDefaults$scc_name$Impl() {\n"
+ " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n"
+ // Force initialization of primitive values we depend on.
+ " ::google::protobuf::internal::InitProtobufDefaults();\n",
+ "scc_name", scc_name);
- for (int i = 0; i < package_parts_.size(); i++) {
- printer->Print("namespace $part$ {\n",
- "part", package_parts_[i]);
+ printer->Indent();
+
+ // Call the InitDefaults() methods for all of our dependencies, to make
+ // sure they get added first.
+ for (int i = 0; i < scc->children.size(); i++) {
+ const SCC* child_scc = scc->children[i];
+ const FileDescriptor* dependency = child_scc->GetRepresentative()->file();
+ // Print the namespace prefix for the dependency.
+ string file_namespace = FileLevelNamespace(dependency);
+ std::map<string, string> variables;
+ variables["file_namespace"] = file_namespace;
+ variables["scc_name"] = ClassName(child_scc->GetRepresentative(), false);
+ bool using_weak_fields = UsingImplicitWeakFields(file_, options_);
+ if (using_weak_fields) {
+ // We're building for lite with implicit weak fields, so we need to handle
+ // the possibility that this InitDefaults function is not linked into the
+ // binary. Some of these might actually be guaranteed to be non-null since
+ // we might have a strong reference to the dependency (via a required
+ // field, for example), but it's simplest to just assume that any of them
+ // could be null.
+ printer->Print(
+ variables,
+ "if (&$file_namespace$::InitDefaults$scc_name$ != NULL) {\n"
+ " $file_namespace$::InitDefaults$scc_name$();\n"
+ "}\n");
+ } else {
+ printer->Print(variables,
+ "$file_namespace$::InitDefaults$scc_name$();\n");
+ }
+ }
+
+ // First construct all the necessary default instances.
+ for (int i = 0; i < message_generators_.size(); i++) {
+ if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) {
+ continue;
+ }
+ // TODO(gerbens) This requires this function to be friend. Remove
+ // the need for this.
+ message_generators_[i]->GenerateFieldDefaultInstances(printer);
+ printer->Print(
+ "{\n"
+ " void* ptr = &$ns$::_$classname$_default_instance_;\n"
+ " new (ptr) $ns$::$classname$();\n",
+ "ns", Namespace(message_generators_[i]->descriptor_),
+ "classname", ClassName(message_generators_[i]->descriptor_));
+ if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) {
+ printer->Print(
+ " ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);\n");
+ }
+ printer->Print("}\n");
}
+
+ // TODO(gerbens) make default instances be the same as normal instances.
+ // Default instances differ from normal instances because they have cross
+ // linked message fields.
+ for (int i = 0; i < message_generators_.size(); i++) {
+ if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) {
+ continue;
+ }
+ printer->Print("$classname$::InitAsDefaultInstance();\n", "classname",
+ QualifiedClassName(message_generators_[i]->descriptor_));
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+ printer->Print(
+ "void InitDefaults$scc_name$() {\n"
+ " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n"
+ " ::google::protobuf::GoogleOnceInit(&once, "
+ "&InitDefaults$scc_name$Impl);\n"
+ "}\n\n",
+ "scc_name", scc_name);
}
-void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
- if (package_parts_.size() > 0) printer->Print("\n");
+void FileGenerator::GenerateInitializationCode(io::Printer* printer) {
+ // Messages depend on the existence of a default instance, which has to
+ // initialized properly. The default instances are allocated in the data
+ // segment, but we can't quite allocate the type directly. The destructors
+ // cannot run at program exit as this could lead to segfaults in a threaded
+ // environment. Hence these instances must be inplace constructed at first
+ // use.
+
+ if (options_.table_driven_parsing) {
+ // TODO(ckennelly): Gate this with the same options flag to enable
+ // table-driven parsing.
+ printer->Print(
+ "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n"
+ " const TableStruct::entries[] "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
+ printer->Indent();
- for (int i = package_parts_.size() - 1; i >= 0; i--) {
- printer->Print("} // namespace $part$\n",
- "part", package_parts_[i]);
+ std::vector<size_t> entries;
+ size_t count = 0;
+ for (int i = 0; i < message_generators_.size(); i++) {
+ size_t value = message_generators_[i]->GenerateParseOffsets(printer);
+ entries.push_back(value);
+ count += value;
+ }
+
+ // We need these arrays to exist, and MSVC does not like empty arrays.
+ if (count == 0) {
+ printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n"
+ "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n"
+ " const TableStruct::aux[] "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
+ printer->Indent();
+
+ std::vector<size_t> aux_entries;
+ count = 0;
+ for (int i = 0; i < message_generators_.size(); i++) {
+ size_t value = message_generators_[i]->GenerateParseAuxTable(printer);
+ aux_entries.push_back(value);
+ count += value;
+ }
+
+ if (count == 0) {
+ printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n"
+ " TableStruct::schema[] "
+ "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
+ printer->Indent();
+
+ size_t offset = 0;
+ size_t aux_offset = 0;
+ for (int i = 0; i < message_generators_.size(); i++) {
+ message_generators_[i]->GenerateParseTable(printer, offset, aux_offset);
+ offset += entries[i];
+ aux_offset += aux_entries[i];
+ }
+
+ if (message_generators_.empty()) {
+ printer->Print("{ NULL, NULL, 0, -1, -1, false },\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+ }
+
+ if (!message_generators_.empty() && options_.table_driven_serialization) {
+ printer->Print(
+ "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] "
+ "= {\n");
+ printer->Indent();
+ std::vector<int> field_metadata_offsets;
+ int idx = 0;
+ for (int i = 0; i < message_generators_.size(); i++) {
+ field_metadata_offsets.push_back(idx);
+ idx += message_generators_[i]->GenerateFieldMetadata(printer);
+ }
+ field_metadata_offsets.push_back(idx);
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "const ::google::protobuf::internal::SerializationTable "
+ "TableStruct::serialization_table[] = {\n");
+ printer->Indent();
+ // We rely on the order we layout the tables to match the order we
+ // calculate them with FlattenMessagesInFile, so we check here that
+ // these match exactly.
+ std::vector<const Descriptor*> calculated_order =
+ FlattenMessagesInFile(file_);
+ GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size());
+ for (int i = 0; i < message_generators_.size(); i++) {
+ GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_);
+ printer->Print(
+ "{$num_fields$, TableStruct::field_metadata + $index$},\n",
+ "classname", message_generators_[i]->classname_, "num_fields",
+ SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]),
+ "index", SimpleItoa(field_metadata_offsets[i]));
+ }
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+ }
+
+ // -----------------------------------------------------------------
+ // All functionality that need private access.
+
+ // Now generate the InitDefaults for each SCC.
+ for (int i = 0; i < message_generators_.size(); i++) {
+ if (IsSCCRepresentative(message_generators_[i]->descriptor_)) {
+ GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), printer);
+ }
}
}
@@ -985,6 +1074,9 @@ void FileGenerator::GenerateBottomHeaderGuard(
}
void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+ if (UsingImplicitWeakFields(file_, options_)) {
+ printer->Print("#include <google/protobuf/implicit_weak_message.h>\n");
+ }
printer->Print(
"#include <google/protobuf/stubs/common.h>\n"
@@ -1114,31 +1206,56 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
void FileGenerator::GenerateGlobalStateFunctionDeclarations(
io::Printer* printer) {
- // Forward-declare the AddDescriptors, AssignDescriptors
- // functions, so that we can declare them to be friends of each class.
+// Forward-declare the AddDescriptors, InitDefaults because these are called
+// by .pb.cc files depending on this file.
printer->Print(
"\n"
"namespace $file_namespace$ {\n"
- "// Internal implementation detail -- do not call these.\n"
+ "// Internal implementation detail -- do not use these members.\n"
"struct $dllexport_decl$TableStruct {\n"
+ // These tables describe how to serialize and parse messages. Used
+ // for table driven code.
" static const ::google::protobuf::internal::ParseTableField entries[];\n"
" static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n"
- " static const ::google::protobuf::internal::ParseTable schema[];\n"
- " static const ::google::protobuf::uint32 offsets[];\n"
+ " static const ::google::protobuf::internal::ParseTable schema[$num$];\n"
" static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n"
" static const ::google::protobuf::internal::SerializationTable "
"serialization_table[];\n"
- // The following function(s) need to be able to access private members of
- // the messages defined in the file. So we make them static members.
- // This is the internal implementation of InitDefaults. It should only
- // be called by InitDefaults which makes sure it will be called only once.
- " static void InitDefaultsImpl();\n"
- "};\n"
- "void $dllexport_decl$AddDescriptors();\n"
- "void $dllexport_decl$InitDefaults();\n"
- "} // namespace $file_namespace$\n",
- "file_namespace", FileLevelNamespace(file_->name()), "dllexport_decl",
+ " static const ::google::protobuf::uint32 offsets[];\n"
+ "};\n",
+ "file_namespace", FileLevelNamespace(file_), "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ",
+ "num", SimpleItoa(std::max(size_t(1), message_generators_.size())));
+ if (HasDescriptorMethods(file_, options_)) {
+ printer->Print(
+ "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+ }
+ for (int i = 0; i < message_generators_.size(); i++) {
+ if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue;
+ string scc_name = ClassName(message_generators_[i]->descriptor_);
+ // TODO(gerbens) Remove the Impl from header. This is solely because
+ // it currently still needs to be a friend of the protos.
+ printer->Print(
+ "void $dllexport_decl$InitDefaults$scc_name$Impl();\n"
+ "void $dllexport_decl$InitDefaults$scc_name$();\n",
+ "scc_name", scc_name, "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+ }
+ // TODO(gerbens) This is for proto1 interoperability. Remove when proto1
+ // is gone.
+ printer->Print(
+ "inline void $dllexport_decl$InitDefaults() {\n", "dllexport_decl",
options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+ for (int i = 0; i < message_generators_.size(); i++) {
+ if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue;
+ string scc_name = ClassName(message_generators_[i]->descriptor_);
+ printer->Print(" InitDefaults$scc_name$();\n", "scc_name", scc_name);
+ }
+ printer->Print("}\n");
+ printer->Print(
+ "} // namespace $file_namespace$\n",
+ "file_namespace", FileLevelNamespace(file_));
}
void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
@@ -1187,41 +1304,6 @@ void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
}
void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
- // An aside about inline functions in .proto.h mode:
- //
- // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally
- // moving much of the inline functions to the .pb.cc file, which can be a
- // significant performance benefit for compilation time, at the expense
- // of non-inline function calls.
- //
- // However, in .proto.h mode, the definition of the internal dependent
- // base class must remain in the header, and can never be out-lined. The
- // dependent base class also needs access to has-bit manipuation
- // functions, so the has-bit functions must be unconditionally inlined in
- // proto_h mode.
- //
- // This gives us three flavors of functions:
- //
- // 1. Functions on the message not used by the internal dependent base
- // class: in .proto.h mode, only some functions are defined on the
- // message class; others are defined on the dependent base class.
- // These are guarded and can be out-lined. These are generated by
- // GenerateInlineMethods, and include has_* bit functions in
- // non-proto_h mode.
- //
- // 2. Functions on the internal dependent base class: these functions
- // are dependent on a template parameter, so they always need to
- // remain in the header.
- //
- // 3. Functions on the message that are used by the dependent base: the
- // dependent base class down casts itself to the message
- // implementation class to access these functions (the has_* bit
- // manipulation functions). Unlike #1, these functions must
- // unconditionally remain in the header. These are emitted by
- // GenerateDependentInlineMethods, even though they are not actually
- // dependent.
-
- printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
// TODO(gerbens) remove pragmas when gcc is no longer used. Current version
// of gcc fires a bogus error when compiled with strict-aliasing.
printer->Print(
@@ -1242,7 +1324,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
"#ifdef __GNUC__\n"
" #pragma GCC diagnostic pop\n"
"#endif // __GNUC__\n");
- printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
for (int i = 0; i < message_generators_.size(); i++) {
if (i > 0) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index e10fe2f3..7e61cbad 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -35,10 +35,12 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
+#include <algorithm>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
+#include <set>
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
@@ -82,16 +84,21 @@ class FileGenerator {
const string& info_path);
void GenerateSource(io::Printer* printer);
+ int NumMessages() const { return message_generators_.size(); }
+ // Similar to GenerateSource but generates only one message
+ void GenerateSourceForMessage(int idx, io::Printer* printer);
+ void GenerateGlobalSource(io::Printer* printer);
+
private:
// Internal type used by GenerateForwardDeclarations (defined in file.cc).
class ForwardDeclarations;
- // Generate the BuildDescriptors() procedure, which builds all descriptors
- // for types defined in the file.
- void GenerateBuildDescriptors(io::Printer* printer);
+ void GenerateSourceIncludes(io::Printer* printer);
+ void GenerateSourceDefaultInstance(int idx, io::Printer* printer);
- void GenerateNamespaceOpeners(io::Printer* printer);
- void GenerateNamespaceClosers(io::Printer* printer);
+ void GenerateInitForSCC(const SCC* scc, io::Printer* printer);
+ void GenerateInitializationCode(io::Printer* printer);
+ void GenerateReflectionInitializationCode(io::Printer* printer);
// For other imports, generates their forward-declarations.
void GenerateForwardDeclarations(io::Printer* printer);
@@ -143,11 +150,23 @@ class FileGenerator {
// a breaking change so we prefer the #undef approach.
void GenerateMacroUndefs(io::Printer* printer);
+ bool IsSCCRepresentative(const Descriptor* d) {
+ return GetSCCRepresentative(d) == d;
+ }
+ const Descriptor* GetSCCRepresentative(const Descriptor* d) {
+ return GetSCC(d)->GetRepresentative();
+ }
+ const SCC* GetSCC(const Descriptor* d) {
+ return scc_analyzer_.GetSCC(d);
+ }
+
+
const FileDescriptor* file_;
const Options options_;
SCCAnalyzer scc_analyzer_;
+
// 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_;
@@ -155,10 +174,8 @@ class FileGenerator {
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_;
+ // These members are just for owning (and thus proper deleting).
+ // Nested (enum/extension)_generators are owned by child messages.
google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_owner_;
google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> >
service_generators_owner_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 68abd0ef..e01e5dca 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -46,6 +46,7 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
@@ -84,7 +85,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// __declspec(dllimport) depending on what is being compiled.
//
Options file_options;
-
+ bool split_source = false;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "dllexport_decl") {
file_options.dllexport_decl = options[i].second;
@@ -98,10 +99,14 @@ bool CppGenerator::Generate(const FileDescriptor* file,
file_options.annotation_guard_name = options[i].second;
} else if (options[i].first == "lite") {
file_options.enforce_lite = true;
+ } else if (options[i].first == "lite_implicit_weak_fields") {
+ file_options.lite_implicit_weak_fields = true;
} else if (options[i].first == "table_driven_parsing") {
file_options.table_driven_parsing = true;
} else if (options[i].first == "table_driven_serialization") {
file_options.table_driven_serialization = true;
+ } else if (options[i].first == "split_source") {
+ split_source = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
@@ -135,14 +140,13 @@ bool CppGenerator::Generate(const FileDescriptor* file,
}
}
- basename.append(".pb");
{
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
- generator_context->Open(basename + ".h"));
+ generator_context->Open(basename + ".pb.h"));
GeneratedCodeInfo annotations;
io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
&annotations);
- string info_path = basename + ".h.meta";
+ string info_path = basename + ".pb.h.meta";
io::Printer printer(output.get(), '$', file_options.annotate_headers
? &annotation_collector
: NULL);
@@ -156,9 +160,24 @@ bool CppGenerator::Generate(const FileDescriptor* file,
}
// Generate cc file.
- {
+ if (split_source) {
+ {
+ // This is the global .cc file, containing enum/services/tables/reflection
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(basename + ".pb.cc"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateGlobalSource(&printer);
+ }
+ for (int i = 0; i < file_generator.NumMessages(); i++) {
+ // TODO(gerbens) Agree on naming scheme.
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ generator_context->Open(basename + "." + SimpleItoa(i) + ".cc"));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateSourceForMessage(i, &printer);
+ }
+ } else {
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
- generator_context->Open(basename + ".cc"));
+ generator_context->Open(basename + ".pb.cc"));
io::Printer printer(output.get(), '$');
file_generator.GenerateSource(&printer);
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 00959796..4aa77d06 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -32,10 +32,11 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <map>
+#include <queue>
#include <vector>
-#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
@@ -105,6 +106,30 @@ bool HasExtension(const Descriptor* descriptor) {
return false;
}
+// Encode [0..63] as 'A'-'Z', 'a'-'z', '0'-'9', '_'
+char Base63Char(int value) {
+ GOOGLE_CHECK_GE(value, 0);
+ if (value < 26) return 'A' + value;
+ value -= 26;
+ if (value < 26) return 'a' + value;
+ value -= 26;
+ if (value < 10) return '0' + value;
+ GOOGLE_CHECK_EQ(value, 10);
+ return '_';
+}
+
+// Given a c identifier has 63 legal characters we can't implement base64
+// encoding. So we return the k least significant "digits" in base 63.
+template <typename I>
+string Base63(I n, int k) {
+ string res;
+ while (k-- > 0) {
+ res += Base63Char(static_cast<int>(n % 63));
+ n /= 63;
+ }
+ return res;
+}
+
} // namespace
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
@@ -137,44 +162,63 @@ const char kThickSeparator[] =
const char kThinSeparator[] =
"// -------------------------------------------------------------------\n";
-string ClassName(const Descriptor* descriptor, bool qualified) {
-
- // Find "outer", the descriptor of the top-level message in which
- // "descriptor" is embedded.
- const Descriptor* outer = descriptor;
- while (outer->containing_type() != NULL) outer = outer->containing_type();
-
- const string& outer_name = outer->full_name();
- string inner_name = descriptor->full_name().substr(outer_name.size());
-
- if (qualified) {
- return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
- } else {
- return outer->name() + DotsToUnderscores(inner_name);
+bool CanInitializeByZeroing(const FieldDescriptor* field) {
+ if (field->is_repeated() || field->is_extension()) return false;
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return field->default_value_enum()->number() == 0;
+ case FieldDescriptor::CPPTYPE_INT32:
+ return field->default_value_int32() == 0;
+ case FieldDescriptor::CPPTYPE_INT64:
+ return field->default_value_int64() == 0;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return field->default_value_uint32() == 0;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return field->default_value_uint64() == 0;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return field->default_value_float() == 0;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return field->default_value_double() == 0;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() == false;
+ default:
+ return false;
}
}
-string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
+string ClassName(const Descriptor* descriptor) {
+ const Descriptor* parent = descriptor->containing_type();
+ string res;
+ if (parent) res += ClassName(parent) + "_";
+ res += descriptor->name();
+ if (IsMapEntryMessage(descriptor)) res += "_DoNotUse";
+ return res;
+}
+
+string ClassName(const EnumDescriptor* enum_descriptor) {
if (enum_descriptor->containing_type() == NULL) {
- if (qualified) {
- return "::" + DotsToColons(enum_descriptor->full_name());
- } else {
- return enum_descriptor->name();
- }
+ return enum_descriptor->name();
} else {
- string result = ClassName(enum_descriptor->containing_type(), qualified);
- result += '_';
- result += enum_descriptor->name();
- return result;
+ return ClassName(enum_descriptor->containing_type()) + "_" +
+ enum_descriptor->name();
}
}
+string Namespace(const string& package) {
+ if (package.empty()) return "";
+ return "::" + DotsToColons(package);
+}
+
string DefaultInstanceName(const Descriptor* descriptor) {
string prefix = descriptor->file()->package().empty() ? "" : "::";
return prefix + DotsToColons(descriptor->file()->package()) + "::_" +
ClassName(descriptor, false) + "_default_instance_";
}
+string ReferenceFunctionName(const Descriptor* descriptor) {
+ return QualifiedClassName(descriptor) + "_Reference";
+}
+
string DependentBaseClassTemplateName(const Descriptor* descriptor) {
return ClassName(descriptor, false) + "_InternalBase";
}
@@ -210,6 +254,30 @@ string EnumValueName(const EnumValueDescriptor* enum_value) {
return result;
}
+int EstimateAlignmentSize(const FieldDescriptor* field) {
+ if (field == NULL) return 0;
+ if (field->is_repeated()) return 8;
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return 1;
+
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_UINT32:
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return 4;
+
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT64:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return 8;
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return -1; // Make compiler happy.
+}
+
string FieldConstantName(const FieldDescriptor *field) {
string field_name = UnderscoresToCamelCase(field->name(), true);
string result = "k" + field_name + "FieldNumber";
@@ -484,19 +552,6 @@ string SafeFunctionName(const Descriptor* descriptor,
return function_name;
}
-bool StaticInitializersForced(const FileDescriptor* file,
- const Options& options) {
- if (HasDescriptorMethods(file, options) || file->extension_count() > 0) {
- return true;
- }
- for (int i = 0; i < file->message_type_count(); ++i) {
- if (HasExtension(file->message_type(i))) {
- return true;
- }
- }
- return false;
-}
-
static bool HasMapFields(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); ++i) {
@@ -672,13 +727,11 @@ void Flatten(const Descriptor* descriptor,
} // namespace
-std::vector<const Descriptor*> FlattenMessagesInFile(
- const FileDescriptor* file) {
- std::vector<const Descriptor*> result;
+void FlattenMessagesInFile(const FileDescriptor* file,
+ std::vector<const Descriptor*>* result) {
for (int i = 0; i < file->message_type_count(); i++) {
- Flatten(file->message_type(i), &result);
+ Flatten(file->message_type(i), result);
}
- return result;
}
bool HasWeakFields(const Descriptor* descriptor) {
@@ -689,6 +742,27 @@ bool HasWeakFields(const FileDescriptor* file) {
return false;
}
+bool UsingImplicitWeakFields(const FileDescriptor* file,
+ const Options& options) {
+ return options.lite_implicit_weak_fields &&
+ GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME;
+}
+
+
+bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options) {
+ return UsingImplicitWeakFields(field->file(), options) &&
+ field->type() == FieldDescriptor::TYPE_MESSAGE &&
+ !field->is_required() && !field->is_repeated() && !field->is_map() &&
+ field->containing_oneof() == NULL &&
+ field->message_type()->file() != field->file();
+}
+
+struct CompareDescriptors {
+ bool operator()(const Descriptor* a, const Descriptor* b) {
+ return a->full_name() < b->full_name();
+ }
+};
+
SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
// Must not have visited already.
GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
@@ -728,10 +802,33 @@ SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
if (scc_desc == descriptor) break;
}
+
+ // The order of descriptors is random and depends how this SCC was
+ // discovered. In-order to ensure maximum stability we sort it by name.
+ std::sort(scc->descriptors.begin(), scc->descriptors.end(),
+ CompareDescriptors());
+ AddChildren(scc);
}
return result;
}
+void SCCAnalyzer::AddChildren(SCC* scc) {
+ std::set<const SCC*> seen;
+ for (int i = 0; i < scc->descriptors.size(); i++) {
+ const Descriptor* descriptor = scc->descriptors[i];
+ for (int j = 0; j < descriptor->field_count(); j++) {
+ const Descriptor* child_msg = descriptor->field(j)->message_type();
+ if (child_msg) {
+ const SCC* child = GetSCC(child_msg);
+ if (child == scc) continue;
+ if (seen.insert(child).second) {
+ scc->children.push_back(child);
+ }
+ }
+ }
+ }
+}
+
MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
if (analysis_cache_.count(scc)) return analysis_cache_[scc];
MessageAnalysis result = MessageAnalysis();
@@ -784,6 +881,46 @@ MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
return analysis_cache_[scc] = result;
}
+void ListAllFields(const Descriptor* d,
+ std::vector<const FieldDescriptor*>* fields) {
+ // Collect sub messages
+ for (int i = 0; i < d->nested_type_count(); i++) {
+ ListAllFields(d->nested_type(i), fields);
+ }
+ // Collect message level extensions.
+ for (int i = 0; i < d->extension_count(); i++) {
+ fields->push_back(d->extension(i));
+ }
+ // Add types of fields necessary
+ for (int i = 0; i < d->field_count(); i++) {
+ fields->push_back(d->field(i));
+ }
+}
+
+void ListAllFields(const FileDescriptor* d,
+ std::vector<const FieldDescriptor*>* fields) {
+ // Collect file level message.
+ for (int i = 0; i < d->message_type_count(); i++) {
+ ListAllFields(d->message_type(i), fields);
+ }
+ // Collect message level extensions.
+ for (int i = 0; i < d->extension_count(); i++) {
+ fields->push_back(d->extension(i));
+ }
+}
+
+void ListAllTypesForServices(const FileDescriptor* fd,
+ std::vector<const Descriptor*>* types) {
+ for (int i = 0; i < fd->service_count(); i++) {
+ const ServiceDescriptor* sd = fd->service(i);
+ for (int j = 0; j < sd->method_count(); j++) {
+ const MethodDescriptor* method = sd->method(j);
+ types->push_back(method->input_type());
+ types->push_back(method->output_type());
+ }
+ }
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 6ae68591..550438dd 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -38,16 +38,13 @@
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_options.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
-
-namespace io {
-class Printer;
-}
-
namespace compiler {
namespace cpp {
@@ -56,6 +53,31 @@ namespace cpp {
extern const char kThickSeparator[];
extern const char kThinSeparator[];
+// Name space of the proto file. This namespace is such that the string
+// "<namespace>::some_name" is the correct fully qualified namespace.
+// This means if the package is empty the namespace is "", and otherwise
+// the namespace is "::foo::bar::...::baz" without trailing semi-colons.
+string Namespace(const string& package);
+inline string Namespace(const FileDescriptor* d) {
+ return Namespace(d->package());
+}
+template <typename Desc>
+string Namespace(const Desc* d) {
+ return Namespace(d->file());
+}
+
+// Returns true if it's safe to reset "field" to zero.
+bool CanInitializeByZeroing(const FieldDescriptor* field);
+
+string ClassName(const Descriptor* descriptor);
+string ClassName(const EnumDescriptor* enum_descriptor);
+template <typename Desc>
+string QualifiedClassName(const Desc* d) {
+ return Namespace(d) + "::" + ClassName(d);
+}
+
+// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very
+// unreadable at the callsite.
// Returns the non-nested type name for the given type. If "qualified" is
// true, prefix the type with the full namespace. For example, if you had:
// package foo.bar;
@@ -64,12 +86,22 @@ extern const char kThinSeparator[];
// ::foo::bar::Baz_Qux
// While the non-qualified version would be:
// Baz_Qux
-string ClassName(const Descriptor* descriptor, bool qualified);
-string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
+inline string ClassName(const Descriptor* descriptor, bool qualified) {
+ return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor);
+}
+
+inline string ClassName(const EnumDescriptor* descriptor, bool qualified) {
+ return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor);
+}
// Fully qualified name of the default_instance of this message.
string DefaultInstanceName(const Descriptor* descriptor);
+// Returns the name of a no-op function that we can call to introduce a linker
+// dependency on the given message type. This is used to implement implicit weak
+// fields.
+string ReferenceFunctionName(const Descriptor* descriptor);
+
// Name of the CRTP class template (for use with proto_h).
// This is a class name, like "ProtoName_InternalBase".
string DependentBaseClassTemplateName(const Descriptor* descriptor);
@@ -92,6 +124,12 @@ string FieldName(const FieldDescriptor* field);
// Get the sanitized name that should be used for the given enum in C++ code.
string EnumValueName(const EnumValueDescriptor* enum_value);
+// Returns an estimate of the compiler's alignment for the field. This
+// can't guarantee to be correct because the generated code could be compiled on
+// different systems with different alignment rules. The estimates below assume
+// 64-bit pointers.
+int EstimateAlignmentSize(const FieldDescriptor* field);
+
// Get the unqualified name that should be used for a field's field
// number constant.
string FieldConstantName(const FieldDescriptor *field);
@@ -150,6 +188,12 @@ string FilenameIdentifier(const string& filename);
// For each .proto file generates a unique namespace. In this namespace global
// definitions are put to prevent collisions.
string FileLevelNamespace(const string& filename);
+inline string FileLevelNamespace(const FileDescriptor* file) {
+ return FileLevelNamespace(file->name());
+}
+inline string FileLevelNamespace(const Descriptor* d) {
+ return FileLevelNamespace(d->file());
+}
// Return the qualified C++ name for a file level symbol.
string QualifiedFileLevelSymbol(const string& package, const string& name);
@@ -225,10 +269,6 @@ inline bool HasFastArraySerialization(const FileDescriptor* file,
return GetOptimizeFor(file, options) == FileOptions::SPEED;
}
-// Returns whether we have to generate code with static initializers.
-bool StaticInitializersForced(const FileDescriptor* file,
- const Options& options);
-
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
@@ -289,12 +329,25 @@ inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
}
// This orders the messages in a .pb.cc as it's outputted by file.cc
-std::vector<const Descriptor*> FlattenMessagesInFile(
- const FileDescriptor* file);
+void FlattenMessagesInFile(const FileDescriptor* file,
+ std::vector<const Descriptor*>* result);
+inline std::vector<const Descriptor*> FlattenMessagesInFile(
+ const FileDescriptor* file) {
+ std::vector<const Descriptor*> result;
+ FlattenMessagesInFile(file, &result);
+ return result;
+}
bool HasWeakFields(const Descriptor* desc);
bool HasWeakFields(const FileDescriptor* desc);
+// Indicates whether we should use implicit weak fields for this file.
+bool UsingImplicitWeakFields(const FileDescriptor* file,
+ const Options& options);
+
+// Indicates whether to treat this field as implicitly weak.
+bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options);
+
// Returns true if the "required" restriction check should be ignored for the
// given field.
inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
@@ -302,8 +355,46 @@ inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
return false;
}
+class LIBPROTOC_EXPORT NamespaceOpener {
+ public:
+ explicit NamespaceOpener(io::Printer* printer) : printer_(printer) {}
+ NamespaceOpener(const string& name, io::Printer* printer)
+ : printer_(printer) {
+ ChangeTo(name);
+ }
+ ~NamespaceOpener() { ChangeTo(""); }
+
+ void ChangeTo(const string& name) {
+ std::vector<string> new_stack_ =
+ Split(name, "::", true);
+ int len = std::min(name_stack_.size(), new_stack_.size());
+ int common_idx = 0;
+ while (common_idx < len) {
+ if (name_stack_[common_idx] != new_stack_[common_idx]) break;
+ common_idx++;
+ }
+ for (int i = name_stack_.size() - 1; i >= common_idx; i--) {
+ printer_->Print("} // namespace $ns$\n", "ns", name_stack_[i]);
+ }
+ name_stack_.swap(new_stack_);
+ for (int i = common_idx; i < name_stack_.size(); i++) {
+ printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]);
+ }
+ }
+
+ private:
+ io::Printer* printer_;
+ std::vector<string> name_stack_;
+};
+
+// Description of each strongly connected component. Note that the order
+// of both the descriptors in this SCC and the order of children is
+// deterministic.
struct SCC {
std::vector<const Descriptor*> descriptors;
+ std::vector<const SCC*> children;
+
+ const Descriptor* GetRepresentative() const { return descriptors[0]; }
};
struct MessageAnalysis {
@@ -357,8 +448,16 @@ class LIBPROTOC_EXPORT SCCAnalyzer {
// Tarjan's Strongly Connected Components algo
NodeData DFS(const Descriptor* descriptor);
+
+ // Add the SCC's that are children of this SCC to its children.
+ void AddChildren(SCC* scc);
};
+void ListAllFields(const FileDescriptor* d,
+ std::vector<const FieldDescriptor*>* fields);
+void ListAllTypesForServices(const FileDescriptor* fd,
+ std::vector<const Descriptor*>* types);
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index da33d29b..d06a1d39 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -114,50 +114,13 @@ MapFieldGenerator::~MapFieldGenerator() {}
void MapFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
- if (HasDescriptorMethods(descriptor_->file(), options_)) {
- printer->Print(
- variables_,
- "public:\n"
- "class $map_classname$ : public "
- "::google::protobuf::internal::MapEntry<$map_classname$, \n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ > {\n"
- "public:\n"
- " typedef ::google::protobuf::internal::MapEntry<$map_classname$, \n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ > SuperType;\n"
- " $map_classname$();\n"
- " $map_classname$(::google::protobuf::Arena* arena);\n"
- " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n"
- " void MergeFrom(const $map_classname$& other);\n"
- " static const Message* internal_default_instance() { return "
- "reinterpret_cast<const "
- "Message*>(&_$map_classname$_default_instance_); }\n"
- " ::google::protobuf::Metadata GetMetadata() const;\n"
- "};\n");
- } else {
- printer->Print(variables_,
- "public:\n"
- "typedef ::google::protobuf::internal::MapEntryLite<\n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ >\n"
- " $map_classname$;\n");
- }
printer->Print(variables_,
- "private:\n"
"::google::protobuf::internal::MapField$lite$<\n"
" $map_classname$,\n"
" $key_cpp$, $val_cpp$,\n"
" $key_wire_type$,\n"
" $val_wire_type$,\n"
- " $default_enum_value$ > $name$_;\n"
- "private:\n");
+ " $default_enum_value$ > $name$_;\n");
}
void MapFieldGenerator::
@@ -262,7 +225,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
" unknown_fields_stream.WriteVarint32($tag$u);\n"
" unknown_fields_stream.WriteVarint32(\n"
- " static_cast<google::protobuf::uint32>(data.size()));\n"
+ " static_cast< ::google::protobuf::uint32>(data.size()));\n"
" unknown_fields_stream.WriteString(data);\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 63ebb3c5..cf9c1233 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -48,6 +48,7 @@
#include <google/protobuf/compiler/cpp/cpp_extension.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
@@ -109,106 +110,6 @@ struct ExtensionRangeSorter {
}
};
-// This returns an estimate of the compiler's alignment for the field. This
-// can't guarantee to be correct because the generated code could be compiled on
-// different systems with different alignment rules. The estimates below assume
-// 64-bit pointers.
-int EstimateAlignmentSize(const FieldDescriptor* field) {
- if (field == NULL) return 0;
- if (field->is_repeated()) return 8;
- switch (field->cpp_type()) {
- case FieldDescriptor::CPPTYPE_BOOL:
- return 1;
-
- case FieldDescriptor::CPPTYPE_INT32:
- case FieldDescriptor::CPPTYPE_UINT32:
- case FieldDescriptor::CPPTYPE_ENUM:
- case FieldDescriptor::CPPTYPE_FLOAT:
- return 4;
-
- case FieldDescriptor::CPPTYPE_INT64:
- case FieldDescriptor::CPPTYPE_UINT64:
- case FieldDescriptor::CPPTYPE_DOUBLE:
- case FieldDescriptor::CPPTYPE_STRING:
- case FieldDescriptor::CPPTYPE_MESSAGE:
- return 8;
- }
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return -1; // Make compiler happy.
-}
-
-// FieldGroup is just a helper for OptimizePadding below. It holds a vector of
-// fields that are grouped together because they have compatible alignment, and
-// a preferred location in the final field ordering.
-class FieldGroup {
- public:
- FieldGroup()
- : preferred_location_(0) {}
-
- // A group with a single field.
- FieldGroup(float preferred_location, const FieldDescriptor* field)
- : preferred_location_(preferred_location),
- fields_(1, field) {}
-
- // Append the fields in 'other' to this group.
- void Append(const FieldGroup& other) {
- if (other.fields_.empty()) {
- return;
- }
- // Preferred location is the average among all the fields, so we weight by
- // the number of fields on each FieldGroup object.
- preferred_location_ =
- (preferred_location_ * fields_.size() +
- (other.preferred_location_ * other.fields_.size())) /
- (fields_.size() + other.fields_.size());
- fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
- }
-
- void SetPreferredLocation(float location) { preferred_location_ = location; }
- const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
-
- // FieldGroup objects sort by their preferred location.
- bool operator<(const FieldGroup& other) const {
- return preferred_location_ < other.preferred_location_;
- }
-
- private:
- // "preferred_location_" is an estimate of where this group should go in the
- // final list of fields. We compute this by taking the average index of each
- // field in this group in the original ordering of fields. This is very
- // approximate, but should put this group close to where its member fields
- // originally went.
- float preferred_location_;
- std::vector<const FieldDescriptor*> fields_;
- // We rely on the default copy constructor and operator= so this type can be
- // used in a vector.
-};
-
-// Helper for the code that emits the Clear() method.
-bool CanInitializeByZeroing(const FieldDescriptor* field) {
- if (field->is_repeated() || field->is_extension()) return false;
- switch (field->cpp_type()) {
- case internal::WireFormatLite::CPPTYPE_ENUM:
- return field->default_value_enum()->number() == 0;
- case internal::WireFormatLite::CPPTYPE_INT32:
- return field->default_value_int32() == 0;
- case internal::WireFormatLite::CPPTYPE_INT64:
- return field->default_value_int64() == 0;
- case internal::WireFormatLite::CPPTYPE_UINT32:
- return field->default_value_uint32() == 0;
- case internal::WireFormatLite::CPPTYPE_UINT64:
- return field->default_value_uint64() == 0;
- case internal::WireFormatLite::CPPTYPE_FLOAT:
- return field->default_value_float() == 0;
- case internal::WireFormatLite::CPPTYPE_DOUBLE:
- return field->default_value_double() == 0;
- case internal::WireFormatLite::CPPTYPE_BOOL:
- return field->default_value_bool() == false;
- default:
- return false;
- }
-}
-
bool IsPOD(const FieldDescriptor* field) {
if (field->is_repeated() || field->is_extension()) return false;
switch (field->cpp_type()) {
@@ -242,133 +143,6 @@ bool CanConstructByZeroing(const FieldDescriptor* field,
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.
-//
-// We try to do this while keeping each field as close as possible to its field
-// number order so that we don't reduce cache locality much for function that
-// access each field in order. Originally, OptimizePadding used declaration
-// order for its decisions, but generated code minus the serializer/parsers uses
-// the output of OptimizePadding as well (stored in
-// MessageGenerator::optimized_order_). Since the serializers use field number
-// order, we use that as a tie-breaker.
-//
-// TODO(ckennelly): If/when we have profiles available for the compiler, use
-// those rather than respect declaration order.
-//
-// We classify each field into a particular "family" of fields, that we perform
-// the same operation on in our generated functions.
-//
-// REPEATED is placed first, as the C++ compiler automatically initializes
-// these fields in layout order.
-//
-// 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), which allows them to be
-// memset.
-//
-// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
-//
-// OTHER these fields are initialized one-by-one.
-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 = 3,
- ZERO_INITIALIZABLE = 4,
- OTHER = 5,
- kMaxFamily
- };
-
- // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
- 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];
-
- Family f = OTHER;
- if (field->is_repeated()) {
- f = REPEATED;
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
- f = STRING;
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- f = MESSAGE;
-
- } else if (CanInitializeByZeroing(field)) {
- f = ZERO_INITIALIZABLE;
- }
-
- const int j = field->number();
- switch (EstimateAlignmentSize(field)) {
- case 1: aligned_to_1[f].push_back(FieldGroup(j, field)); break;
- case 4: aligned_to_4[f].push_back(FieldGroup(j, field)); break;
- case 8: aligned_to_8[f].push_back(FieldGroup(j, field)); break;
- default:
- GOOGLE_LOG(FATAL) << "Unknown alignment size.";
- }
- }
-
- // For each family, group fields to optimize padding.
- for (int f = 0; f < kMaxFamily; f++) {
- // Now group fields aligned to 1 byte into sets of 4, and treat those like a
- // single field aligned to 4 bytes.
- for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
- FieldGroup field_group;
- for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
- field_group.Append(aligned_to_1[f][j]);
- }
- aligned_to_4[f].push_back(field_group);
- }
- // Sort by preferred location to keep fields as close to their field number
- // order as possible. Using stable_sort ensures that the output is
- // consistent across runs.
- std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
-
- // Now group fields aligned to 4 bytes (or the 4-field groups created above)
- // into pairs, and treat those like a single field aligned to 8 bytes.
- for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
- FieldGroup field_group;
- for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
- field_group.Append(aligned_to_4[f][j]);
- }
- if (i == aligned_to_4[f].size() - 1) {
- if (f == OTHER) {
- // Move incomplete 4-byte block to the beginning. This is done to
- // pair with the (possible) leftover blocks from the
- // ZERO_INITIALIZABLE family.
- field_group.SetPreferredLocation(-1);
- } else {
- // Move incomplete 4-byte block to the end.
- field_group.SetPreferredLocation(fields->size() + 1);
- }
- }
- aligned_to_8[f].push_back(field_group);
- }
- // Sort by preferred location.
- std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
- }
-
- // Now pull out all the FieldDescriptors in order.
- fields->clear();
- for (int f = 0; f < kMaxFamily; ++f) {
- for (int i = 0; i < aligned_to_8[f].size(); ++i) {
- fields->insert(fields->end(),
- aligned_to_8[f][i].fields().begin(),
- aligned_to_8[f][i].fields().end());
- }
- }
-}
-
-
// Emits an if-statement with a condition that evaluates to true if |field| is
// considered non-default (will be sent over the wire), for message types
// without true field presence. Should only be called if
@@ -423,25 +197,31 @@ bool HasHasMethod(const FieldDescriptor* field) {
void CollectMapInfo(const Descriptor* descriptor,
std::map<string, string>* variables) {
GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+ std::map<string, string>& vars = *variables;
const FieldDescriptor* key = descriptor->FindFieldByName("key");
const FieldDescriptor* val = descriptor->FindFieldByName("value");
- (*variables)["key"] = PrimitiveTypeName(key->cpp_type());
+ vars["key_cpp"] = PrimitiveTypeName(key->cpp_type());
switch (val->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- (*variables)["val"] = FieldMessageTypeName(val);
+ vars["val_cpp"] = FieldMessageTypeName(val);
break;
case FieldDescriptor::CPPTYPE_ENUM:
- (*variables)["val"] = ClassName(val->enum_type(), true);
+ vars["val_cpp"] = ClassName(val->enum_type(), true);
break;
default:
- (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
- }
- (*variables)["key_wire_type"] =
- "::google::protobuf::internal::WireFormatLite::TYPE_" +
- ToUpper(DeclaredTypeMethodName(key->type()));
- (*variables)["val_wire_type"] =
- "::google::protobuf::internal::WireFormatLite::TYPE_" +
- ToUpper(DeclaredTypeMethodName(val->type()));
+ vars["val_cpp"] = PrimitiveTypeName(val->cpp_type());
+ }
+ vars["key_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ vars["val_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+ if (descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ vars["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ vars["default_enum_value"] = "0";
+ }
}
// Does the given field have a private (internal helper only) has_$name$()
@@ -531,21 +311,22 @@ void SetUnknkownFieldsVariable(const Descriptor* descriptor,
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
+ int index_in_file_messages,
const Options& options,
SCCAnalyzer* scc_analyzer)
: descriptor_(descriptor),
+ index_in_file_messages_(index_in_file_messages),
classname_(ClassName(descriptor, false)),
options_(options),
field_generators_(descriptor, options),
max_has_bit_index_(0),
- nested_generators_(new google::protobuf::scoped_ptr<
- MessageGenerator>[descriptor->nested_type_count()]),
enum_generators_(
new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
extension_generators_(new google::protobuf::scoped_ptr<
ExtensionGenerator>[descriptor->extension_count()]),
use_dependent_base_(false),
num_weak_fields_(0),
+ message_layout_helper_(new PaddingOptimizer()),
scc_analyzer_(scc_analyzer) {
// Compute optimized field order to be used for layout and initialization
// purposes.
@@ -557,7 +338,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
optimized_order_.push_back(field);
}
}
- OptimizePadding(&optimized_order_, options_);
+
+ message_layout_helper_->OptimizeLayout(&optimized_order_, options_);
if (HasFieldPresence(descriptor_->file())) {
// We use -1 as a sentinel.
@@ -573,11 +355,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
}
}
- for (int i = 0; i < descriptor->nested_type_count(); i++) {
- nested_generators_[i].reset(new MessageGenerator(descriptor->nested_type(i),
- options, scc_analyzer));
- }
-
for (int i = 0; i < descriptor->enum_type_count(); i++) {
enum_generators_[i].reset(
new EnumGenerator(descriptor->enum_type(i), options));
@@ -603,6 +380,9 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
}
table_driven_ = TableDrivenParsingEnabled(descriptor_, options_);
+
+ scc_name_ =
+ ClassName(scc_analyzer_->GetSCC(descriptor_)->GetRepresentative(), false);
}
MessageGenerator::~MessageGenerator() {}
@@ -620,14 +400,6 @@ size_t MessageGenerator::HasBitsSize() const {
return sizeof_has_bits;
}
-void MessageGenerator::Flatten(std::vector<MessageGenerator*>* list) {
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- nested_generators_[i]->Flatten(list);
- }
- index_in_file_messages_ = list->size();
- list->push_back(this);
-}
-
void MessageGenerator::AddGenerators(
std::vector<EnumGenerator*>* enum_generators,
std::vector<ExtensionGenerator*>* extension_generators) {
@@ -1010,8 +782,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
}
// Generate type-specific accessors.
- field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
- is_inline);
+ field_generators_.get(field).GenerateInlineAccessorDefinitions(
+ printer, /* is_inline = */ true);
printer->Print("\n");
}
@@ -1056,7 +828,42 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) {
void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
+ if (IsMapEntryMessage(descriptor_)) {
+ std::map<string, string> vars;
+ vars["classname"] = classname_;
+ CollectMapInfo(descriptor_, &vars);
+ vars["lite"] =
+ HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite";
+ printer->Print(
+ vars,
+ "class $classname$ : public "
+ "::google::protobuf::internal::MapEntry$lite$<$classname$, \n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > {\n"
+ "public:\n"
+ " typedef ::google::protobuf::internal::MapEntry$lite$<$classname$, \n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > SuperType;\n"
+ " $classname$();\n"
+ " $classname$(::google::protobuf::Arena* arena);\n"
+ " void MergeFrom(const $classname$& other);\n"
+ " static const $classname$* internal_default_instance() { return "
+ "reinterpret_cast<const "
+ "$classname$*>(&_$classname$_default_instance_); }\n");
+ if (HasDescriptorMethods(descriptor_->file(), options_)) {
+ printer->Print(
+ " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n"
+ " ::google::protobuf::Metadata GetMetadata() const;\n"
+ "};\n");
+ } else {
+ printer->Print("};\n");
+ }
+ return;
+ }
if (use_dependent_base_) {
GenerateDependentBaseClassDefinition(printer);
printer->Print("\n");
@@ -1109,26 +916,23 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
- // Generate move constructor and move assignment operator for types other than
- // Any.
- if (!IsAnyMessage(descriptor_)) {
- printer->Print(vars,
- "#if LANG_CXX11\n"
- "$classname$($classname$&& from) noexcept\n"
- " : $classname$() {\n"
- " *this = ::std::move(from);\n"
- "}\n"
- "\n"
- "inline $classname$& operator=($classname$&& from) noexcept {\n"
- " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n"
- " if (this != &from) InternalSwap(&from);\n"
- " } else {\n"
- " CopyFrom(from);\n"
- " }\n"
- " return *this;\n"
- "}\n"
- "#endif\n");
- }
+ // Generate move constructor and move assignment operator.
+ printer->Print(vars,
+ "#if LANG_CXX11\n"
+ "$classname$($classname$&& from) noexcept\n"
+ " : $classname$() {\n"
+ " *this = ::std::move(from);\n"
+ "}\n"
+ "\n"
+ "inline $classname$& operator=($classname$&& from) noexcept {\n"
+ " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n"
+ " if (this != &from) InternalSwap(&from);\n"
+ " } else {\n"
+ " CopyFrom(from);\n"
+ " }\n"
+ " return *this;\n"
+ "}\n"
+ "#endif\n");
SetUnknkownFieldsVariable(descriptor_, options_, &vars);
if (PublicUnknownFieldsAccessors(descriptor_)) {
@@ -1199,6 +1003,7 @@ GenerateClassDefinition(io::Printer* printer) {
vars["message_index"] = SimpleItoa(index_in_file_messages_);
printer->Print(
vars,
+ "static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY\n"
"static inline const $classname$* internal_default_instance() {\n"
" return reinterpret_cast<const $classname$*>(\n"
" &_$classname$_default_instance_);\n"
@@ -1358,6 +1163,8 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print("typedef $nested_full_name$ $nested_name$;\n",
"nested_name", nested_type->name(),
"nested_full_name", ClassName(nested_type, false));
+ printer->Annotate("nested_full_name", nested_type);
+ printer->Annotate("nested_name", nested_type);
}
}
@@ -1548,14 +1355,13 @@ GenerateClassDefinition(io::Printer* printer) {
// The TableStruct struct needs access to the private parts, in order to
// construct the offsets of all members.
- //
- // Some InitDefault and Shutdown are defined as static member functions of
- // TableStruct such that they are also allowed to access private members.
+ // TODO(gerbens) Remove the friend for InitDefaults.
printer->Print(
- "friend struct $file_namespace$::TableStruct;\n",
+ "friend struct ::$file_namespace$::TableStruct;\n"
+ "friend void ::$file_namespace$::InitDefaults$scc_name$Impl();\n",
// Vars.
- "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
printer->Outdent();
printer->Print("};");
@@ -1577,7 +1383,7 @@ GenerateDependentInlineMethods(io::Printer* printer) {
void MessageGenerator::
GenerateInlineMethods(io::Printer* printer, bool is_inline) {
if (IsMapEntryMessage(descriptor_)) return;
- GenerateFieldAccessorDefinitions(printer, is_inline);
+ GenerateFieldAccessorDefinitions(printer, /* is_inline = */ true);
// Generate oneof_case() functions.
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -1634,7 +1440,8 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
std::map<string, string> vars;
- vars["classname"] = classname_;
+ vars["classname"] = ClassName(descriptor_);
+ vars["classtype"] = QualifiedClassName(descriptor_);
vars["offset"] = SimpleItoa(offset);
vars["aux_offset"] = SimpleItoa(aux_offset);
@@ -1661,48 +1468,34 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
printer->Print(vars, "-1,\n");
} else {
printer->Print(vars,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
- " $classname$, _has_bits_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classtype$, _has_bits_),\n");
}
if (descriptor_->oneof_decl_count() > 0) {
printer->Print(vars,
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
- " $classname$, _oneof_case_),\n");
+ " $classtype$, _oneof_case_),\n");
} else {
printer->Print("-1, // no _oneof_case_\n");
}
if (descriptor_->extension_range_count() > 0) {
printer->Print(vars,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "_extensions_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, "
+ "_extensions_),\n");
} else {
printer->Print("-1, // no _extensions_\n");
}
// TODO(ckennelly): Consolidate this with the calculation for
// AuxillaryParseTableField.
- std::vector<string> package_parts;
-
- const Descriptor* outer = descriptor_;
- while (outer->containing_type() != NULL) {
- outer = outer->containing_type();
- }
-
- package_parts = Split(
- outer->full_name(), ".", true);
- // outer->full_name() contains the class itself. Remove it as it is
- // used in the name of the default instance variable.
- GOOGLE_DCHECK_NE(package_parts.size(), 0);
- package_parts.back().clear();
-
- vars["ns"] = Join(package_parts, "::");
+ vars["ns"] = Namespace(descriptor_);
printer->Print(vars,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
- " $classname$, _internal_metadata_),\n"
- "&::$ns$_$classname$_default_instance_,\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classtype$, _internal_metadata_),\n"
+ "&$ns$::_$classname$_default_instance_,\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(vars, "true,\n");
@@ -1717,15 +1510,14 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
int has_offset) {
- if (IsMapEntryMessage(descriptor_)) return;
-
std::map<string, string> vars;
- vars["classname"] = classname_;
+ vars["classname"] = QualifiedClassName(descriptor_);
vars["offset"] = SimpleItoa(offset);
- vars["has_bits_offsets"] = HasFieldPresence(descriptor_->file())
- ? SimpleItoa(offset + has_offset)
- : "-1";
+ vars["has_bits_offsets"] =
+ HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)
+ ? SimpleItoa(offset + has_offset)
+ : "-1";
printer->Print(vars,
"{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n");
@@ -1804,6 +1596,8 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
return 0;
}
+ string full_classname = QualifiedClassName(descriptor_);
+
std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_);
if (IsMapEntryMessage(descriptor_)) {
for (int i = 0; i < 2; i++) {
@@ -1812,9 +1606,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
field->number(), WireFormat::WireTypeForFieldType(field->type()));
std::map<string, string> vars;
- vars["classname"] = classname_;
- vars["parent_classname"] =
- ClassName(descriptor_->containing_type(), false);
+ vars["classname"] = QualifiedClassName(descriptor_);
vars["field_name"] = FieldName(field);
vars["tag"] = SimpleItoa(tag);
vars["hasbit"] = SimpleItoa(i);
@@ -1824,23 +1616,18 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
GOOGLE_CHECK(!IsMapEntryMessage(field->message_type()));
{
vars["ptr"] =
- QualifiedFileLevelSymbol(
- field->message_type()->file()->package(),
- FileLevelNamespace(field->message_type()->file()->name())) +
+ "::" + FileLevelNamespace(field->message_type()) +
"::TableStruct::serialization_table + " +
SimpleItoa(FindMessageIndexInFile(field->message_type()));
}
}
- vars["extra"] = HasDescriptorMethods(descriptor_->file(), options_)
- ? "::SuperType"
- : "";
printer->Print(vars,
"{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
- "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$"
- "classname$$extra$>, $field_name$_), $tag$,"
+ "::google::protobuf::internal::MapEntryHelper<$classname$::"
+ "SuperType>, $field_name$_), $tag$,"
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
- "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$"
- "classname$$extra$>, _has_bits_) * 8 + $hasbit$, $type$, "
+ "::google::protobuf::internal::MapEntryHelper<$classname$::"
+ "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, "
"$ptr$},\n");
}
return 2;
@@ -1848,7 +1635,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
printer->Print(
"{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
"_cached_size_), 0, 0, 0, NULL},\n",
- "classname", classname_);
+ "classname", full_classname);
std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
sorted_extensions.push_back(descriptor_->extension_range(i));
@@ -1868,7 +1655,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
"::google::protobuf::internal::FieldMetadata::kSpecial, "
"reinterpret_cast<const "
"void*>(::google::protobuf::internal::ExtensionSerializer)},\n",
- "classname", classname_, "start", SimpleItoa(range->start), "end",
+ "classname", full_classname, "start", SimpleItoa(range->start), "end",
SimpleItoa(range->end));
}
if (i == sorted.size()) break;
@@ -1886,14 +1673,14 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
classfieldname = field->containing_oneof()->name();
}
std::map<string, string> vars;
- vars["classname"] = classname_;
+ vars["classname"] = full_classname;
vars["field_name"] = classfieldname;
vars["tag"] = SimpleItoa(tag);
vars["ptr"] = "NULL";
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (IsMapEntryMessage(field->message_type())) {
vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type()));
- vars["fieldclassname"] = ClassName(field->message_type(), false);
+ vars["fieldclassname"] = QualifiedClassName(field->message_type());
printer->Print(vars,
"{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
"classname$, $field_name$_), $tag$, $idx$, "
@@ -1901,15 +1688,13 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
"reinterpret_cast<const void*>(static_cast< "
"::google::protobuf::internal::SpecialSerializer>("
"::google::protobuf::internal::MapFieldSerializer< "
- "::google::protobuf::internal::MapEntryToMapField<$classname$::$"
- "fieldclassname$>::MapFieldType, "
+ "::google::protobuf::internal::MapEntryToMapField<"
+ "$fieldclassname$>::MapFieldType, "
"TableStruct::serialization_table>))},\n");
continue;
} else {
vars["ptr"] =
- QualifiedFileLevelSymbol(
- field->message_type()->file()->package(),
- FileLevelNamespace(field->message_type()->file()->name())) +
+ "::" + FileLevelNamespace(field->message_type()) +
"::TableStruct::serialization_table + " +
SimpleItoa(FindMessageIndexInFile(field->message_type()));
}
@@ -1960,40 +1745,20 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
"_internal_metadata_), 0, ~0u, "
"::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const "
"void*>($serializer$)},\n",
- "classname", classname_, "serializer", serializer);
+ "classname", full_classname, "serializer", serializer);
return num_field_metadata;
}
-void MessageGenerator::
-GenerateDefaultInstanceAllocator(io::Printer* printer) {
- // Construct the default instances of all fields, as they will be used
- // when creating the default instance of the entire message.
+void MessageGenerator::GenerateFieldDefaultInstances(io::Printer* printer) {
+ // Construct the default instances for all fields that need one.
for (int i = 0; i < descriptor_->field_count(); i++) {
field_generators_.get(descriptor_->field(i))
.GenerateDefaultInstanceAllocator(printer);
}
-
- // Construct the default instance. We can't call InitAsDefaultInstance() yet
- // because we need to make sure all default instances that this one might
- // depend on are constructed first.
- printer->Print("_$classname$_default_instance_._instance.DefaultConstruct();\n"
- "::google::protobuf::internal::OnShutdownDestroyMessage(\n"
- " &_$classname$_default_instance_);",
- "classname", classname_);
}
void MessageGenerator::
GenerateDefaultInstanceInitializer(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) {
- printer->Print(
- "_$classname$_default_instance_._instance.get_mutable()->set_default_instance(_$"
- "classname$_default_instance_._instance.get_mutable());\n"
- "_$classname$_default_instance_._instance.get_mutable()->InitAsDefaultInstance();"
- "\n",
- "classname", classname_);
- return;
- }
-
// 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
@@ -2016,10 +1781,11 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
}
name += FieldName(field);
printer->Print(
- "$name$_ = const_cast< $type$*>(\n"
+ "$ns$::$name$_ = const_cast< $type$*>(\n"
" $type$::internal_default_instance());\n",
// Vars.
- "name", name, "type", FieldMessageTypeName(field));
+ "name", name, "type", FieldMessageTypeName(field), "ns",
+ Namespace(descriptor_));
} else if (field->containing_oneof() &&
HasDescriptorMethods(descriptor_->file(), options_)) {
field_generators_.get(descriptor_->field(i))
@@ -2031,31 +1797,41 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
if (IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "$classname$::$classname$() {}\n"
+ "$classname$::$classname$(::google::protobuf::Arena* arena) : "
+ "SuperType(arena) {}\n"
+ "void $classname$::MergeFrom(const $classname$& other) {\n"
+ " MergeFromInternal(other);\n"
+ "}\n",
+ "classname", classname_);
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
- "$parent$::$classname$::$classname$() {}\n"
- "$parent$::$classname$::$classname$(::google::protobuf::Arena* arena) : "
- "SuperType(arena) {}\n"
- "::google::protobuf::Metadata $parent$::$classname$::GetMetadata() const {\n"
- " $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return $file_namespace$::file_level_metadata[$index$];\n"
+ "::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
+ " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n"
+ " return ::$file_namespace$::file_level_metadata[$index$];\n"
"}\n"
- "void $parent$::$classname$::MergeFrom(\n"
+ "void $classname$::MergeFrom(\n"
" const ::google::protobuf::Message& other) {\n"
" ::google::protobuf::Message::MergeFrom(other);\n"
"}\n"
- "void $parent$::$classname$::MergeFrom(const $classname$& other) {\n"
- " MergeFromInternal(other);\n"
- "}\n"
"\n",
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()),
- "parent", ClassName(descriptor_->containing_type(), false),
+ "file_namespace", FileLevelNamespace(descriptor_),
"classname", classname_, "index",
SimpleItoa(index_in_file_messages_));
}
return;
}
+ // TODO(gerbens) Remove this function. With a little bit of cleanup and
+ // refactoring this is superfluous.
+ printer->Print("void $classname$::InitAsDefaultInstance() {\n", "classname",
+ classname_);
+ printer->Indent();
+ GenerateDefaultInstanceInitializer(printer);
+ printer->Outdent();
+ printer->Print("}\n");
+
if (IsAnyMessage(descriptor_)) {
printer->Print(
"void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
@@ -2134,23 +1910,24 @@ GenerateClassMethods(io::Printer* printer) {
if (options_.table_driven_serialization) {
printer->Print(
- "const void* $classname$::InternalGetTable() const {\n"
- " return $file_namespace$::TableStruct::serialization_table + $index$;\n"
- "}\n"
- "\n",
- "classname", classname_, "index", SimpleItoa(index_in_file_messages_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "const void* $classname$::InternalGetTable() const {\n"
+ " return ::$file_namespace$::TableStruct::serialization_table + "
+ "$index$;\n"
+ "}\n"
+ "\n",
+ "classname", classname_, "index", SimpleItoa(index_in_file_messages_),
+ "file_namespace", FileLevelNamespace(descriptor_));
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
"::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return "
+ " return ::"
"$file_namespace$::file_level_metadata[kIndexInFileMessages];\n"
"}\n"
"\n",
"classname", classname_, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ FileLevelNamespace(descriptor_));
} else {
printer->Print(
"::std::string $classname$::GetTypeName() const {\n"
@@ -2224,7 +2001,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
WireFormat::TagSize(field->number(), field->type());
std::map<string, string> vars;
- vars["classname"] = classname_;
+ vars["classname"] = QualifiedClassName(descriptor_);
if (field->containing_oneof() != NULL) {
vars["name"] = field->containing_oneof()->name();
vars["presence"] = SimpleItoa(field->containing_oneof()->index());
@@ -2280,23 +2057,8 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
last_field_number++;
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
- std::vector<string> package_parts;
-
- const Descriptor* outer = field->message_type();
- while (outer->containing_type() != NULL) {
- outer = outer->containing_type();
- }
-
- package_parts = Split(
- outer->full_name(), ".", true);
- // outer->full_name() contains the class itself. Remove it as it is
- // used in the name of the default instance variable.
- GOOGLE_DCHECK_NE(package_parts.size(), 0);
- package_parts.back().clear();
-
if (field->is_map()) {
- vars["classname"] = ClassName(field->containing_type(), false) +
- "::" + ClassName(field->message_type(), false);
+ vars["classname"] = QualifiedClassName(field->message_type());
printer->Print(vars,
"{::google::protobuf::internal::AuxillaryParseTableField::map_"
"aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n");
@@ -2305,13 +2067,15 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
} else {
vars["classname"] = ClassName(field->message_type(), false);
}
- vars["ns"] = Join(package_parts, "::");
+ vars["ns"] = Namespace(field->message_type());
vars["type"] = FieldMessageTypeName(field);
- vars["file_namespace"] = FileLevelNamespace(outer->file()->name());
+ vars["file_namespace"] =
+ FileLevelNamespace(field->message_type());
- printer->Print(vars,
+ printer->Print(
+ vars,
"{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n"
- " &::$ns$_$classname$_default_instance_,\n");
+ " &$ns$::_$classname$_default_instance_,\n");
bool dont_emit_table =
!TableDrivenParsingEnabled(field->message_type(), options_);
@@ -2320,8 +2084,8 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
printer->Print(" NULL,\n");
} else {
printer->Print(vars,
- " ::$ns$$file_namespace$::TableStruct::schema +\n"
- " ::$ns$$classname$::kIndexInFileMessages,\n");
+ " ::$file_namespace$::TableStruct::schema +\n"
+ " $ns$::$classname$::kIndexInFileMessages,\n");
}
printer->Print("}},\n");
@@ -2333,8 +2097,9 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
case FieldOptions::STRING:
vars["default"] =
field->default_value_string().empty()
- ? "&::google::protobuf::internal::fixed_address_empty_string"
- : "&" + classname_ + "::_default_" + FieldName(field) + "_";
+ ? "&::google::protobuf::internal::fixed_address_empty_string"
+ : "&" + Namespace(field) + " ::" + classname_ +
+ "::_default_" + FieldName(field) + "_";
break;
case FieldOptions::CORD:
case FieldOptions::STRING_PIECE:
@@ -2360,11 +2125,11 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
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_;
+ string full_classname = QualifiedClassName(descriptor_);
+ variables["classname"] = full_classname;
- if (HasFieldPresence(descriptor_->file())) {
+ if (HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)) {
printer->Print(
variables,
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
@@ -2405,27 +2170,29 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->containing_oneof() || field->options().weak()) {
- printer->Print(
- "offsetof($classname$DefaultTypeInternal, $name$_),\n",
- "classname", classname_, "name", FieldName(field));
+ printer->Print("offsetof($classname$DefaultTypeInternal, $name$_),\n",
+ "classname", full_classname, "name", FieldName(field));
} else {
printer->Print(
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "$name$_),\n",
- "classname", classname_,
- "name", FieldName(field));
+ "$name$_),\n",
+ "classname", full_classname, "name", FieldName(field));
}
}
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
printer->Print(
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
- "classname", classname_,
- "name", oneof->name());
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n",
+ "classname", full_classname, "name", oneof->name());
}
- if (HasFieldPresence(descriptor_->file())) {
+ if (IsMapEntryMessage(descriptor_)) {
+ entries += 2;
+ printer->Print(
+ "0,\n"
+ "1,\n");
+ } else if (HasFieldPresence(descriptor_->file())) {
entries += has_bit_indices_.size();
for (int i = 0; i < has_bit_indices_.size(); i++) {
const string index = has_bit_indices_[i] >= 0 ?
@@ -2700,27 +2467,28 @@ GenerateStructors(io::Printer* printer) {
"$classname$::$classname$()\n"
" : $initializer$ {\n"
" if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n"
- " $file_namespace$::InitDefaults();\n"
+ " ::$file_namespace$::InitDefaults$scc_name$();\n"
" }\n"
" SharedCtor();\n"
" // @@protoc_insertion_point(constructor:$full_name$)\n"
"}\n",
"classname", classname_, "full_name", descriptor_->full_name(),
- "initializer", initializer_null, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ "scc_name", scc_name_, "initializer", initializer_null, "file_namespace",
+ FileLevelNamespace(descriptor_));
if (SupportsArenas(descriptor_)) {
printer->Print(
"$classname$::$classname$(::google::protobuf::Arena* arena)\n"
" : $initializer$ {\n"
- " $file_namespace$::InitDefaults();\n"
+ " ::$file_namespace$::InitDefaults$scc_name$();\n"
" SharedCtor();\n"
" RegisterArenaDtor(arena);\n"
" // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
"}\n",
"initializer", initializer_with_arena, "classname", classname_,
"superclass", superclass, "full_name", descriptor_->full_name(),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
}
// Generate the copy constructor.
@@ -2865,23 +2633,23 @@ GenerateStructors(io::Printer* printer) {
!descriptor_->options().no_standard_descriptor_accessor()) {
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
- " $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return "
+ " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n"
+ " return ::"
"$file_namespace$::file_level_metadata[kIndexInFileMessages]."
"descriptor;\n"
"}\n"
"\n",
"classname", classname_, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ FileLevelNamespace(descriptor_));
}
printer->Print(
"const $classname$& $classname$::default_instance() {\n"
- " $file_namespace$::InitDefaults();\n"
+ " ::$file_namespace$::InitDefaults$scc_name$();\n"
" return *internal_default_instance();\n"
"}\n\n",
- "classname", classname_, "file_namespace",
- FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "scc_name", scc_name_, "file_namespace",
+ FileLevelNamespace(descriptor_));
if (SupportsArenas(descriptor_)) {
printer->Print(
@@ -2930,6 +2698,9 @@ bool MessageGenerator::MaybeGenerateOptionalFieldCondition(
void MessageGenerator::
GenerateClear(io::Printer* printer) {
+ // Performance tuning parameters
+ const int kMaxUnconditionalPrimitiveBytesClear = 4;
+
printer->Print(
"void $classname$::Clear() {\n"
"// @@protoc_insertion_point(message_clear_start:$full_name$)\n",
@@ -2951,6 +2722,17 @@ GenerateClear(io::Printer* printer) {
}
int last_i = -1;
+ int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear;
+ for (int i = 0; i < optimized_order_.size(); i++) {
+ const FieldDescriptor* field = optimized_order_[i];
+
+ if (!CanInitializeByZeroing(field)) {
+ continue;
+ }
+
+ unconditional_budget -= EstimateAlignmentSize(field);
+ }
+
for (int i = 0; i < optimized_order_.size(); ) {
// Detect infinite loops.
GOOGLE_CHECK_NE(i, last_i);
@@ -2998,7 +2780,8 @@ GenerateClear(io::Printer* printer) {
if (last_chunk == -1) {
last_chunk = chunk;
last_chunk_start = i;
- } else if (chunk != last_chunk) {
+ } else if ((memset_run_start == -1 || unconditional_budget < 0) &&
+ chunk != last_chunk) {
// Emit the fields for this chunk so far.
break;
}
@@ -3012,6 +2795,11 @@ GenerateClear(io::Printer* printer) {
last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
}
+ if (memset_run_start != memset_run_end && unconditional_budget >= 0) {
+ // Flush the memset fields.
+ goto flush;
+ }
+
// Step 4: Non-repeated, non-zero initializable fields.
for (; i < optimized_order_.size(); i++) {
const FieldDescriptor* field = optimized_order_[i];
@@ -3037,6 +2825,8 @@ GenerateClear(io::Printer* printer) {
last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
}
+flush:
+
if (last_chunk != -1) {
GOOGLE_DCHECK_NE(-1, last_chunk_start);
GOOGLE_DCHECK_NE(-1, last_chunk_end);
@@ -3044,7 +2834,10 @@ GenerateClear(io::Printer* printer) {
const int count = popcnt(last_chunk_mask);
const bool have_outer_if = HasFieldPresence(descriptor_->file()) &&
- (last_chunk_start != last_chunk_end);
+ (last_chunk_start != last_chunk_end) &&
+ (memset_run_start != last_chunk_start ||
+ memset_run_end != last_chunk_end ||
+ unconditional_budget < 0);
if (have_outer_if) {
// Check (up to) 8 has_bits at a time if we have more than one field in
@@ -3613,12 +3406,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print(
"return ::google::protobuf::internal::MergePartialFromCodedStream$lite$(\n"
" this,\n"
- " $file_namespace$::TableStruct::schema[\n"
+ " ::$file_namespace$::TableStruct::schema[\n"
" $classname$::kIndexInFileMessages],\n"
" input);\n",
- "classname", classname_,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()),
- "lite", lite);
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_), "lite", lite);
printer->Outdent();
@@ -3631,17 +3423,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
" ::google::protobuf::uint32 tag;\n");
if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
- // Use LazyStringOutputString to avoid initializing unknown fields string
- // unless it is actually needed. For the same reason, disable eager refresh
- // on the CodedOutputStream.
printer->Print(
- " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
- " ::google::protobuf::NewPermanentCallback(&_internal_metadata_,\n"
- " &::google::protobuf::internal::InternalMetadataWithArenaLite::\n"
- " mutable_unknown_fields));\n"
- " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
- " &unknown_fields_string, false);\n",
- "classname", classname_);
+ " ::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(\n"
+ " &_internal_metadata_);\n"
+ " ::google::protobuf::io::StringOutputStream unknown_fields_output(\n"
+ " unknown_fields_setter.buffer());\n"
+ " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
+ " &unknown_fields_output, false);\n",
+ "classname", classname_);
}
printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 352069eb..cf64f483 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -43,6 +43,7 @@
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
@@ -62,12 +63,10 @@ class ExtensionGenerator; // extension.h
class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
- MessageGenerator(const Descriptor* descriptor, const Options& options,
- SCCAnalyzer* scc_analyzer);
+ MessageGenerator(const Descriptor* descriptor, int index_in_file_messages,
+ const Options& options, SCCAnalyzer* scc_analyzer);
~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);
@@ -96,8 +95,8 @@ class MessageGenerator {
// Generate extra fields
void GenerateExtraDefaultFields(io::Printer* printer);
- // Generates code that allocates the message's default instance.
- void GenerateDefaultInstanceAllocator(io::Printer* printer);
+ // Generates code that creates default instances for fields.
+ void GenerateFieldDefaultInstances(io::Printer* printer);
// Generates code that initializes the message's default instance. This
// is separate from allocating because all default instances must be
@@ -208,6 +207,7 @@ class MessageGenerator {
std::vector<uint32> RequiredFieldsBitMask() const;
const Descriptor* descriptor_;
+ int index_in_file_messages_;
string classname_;
Options options_;
FieldGeneratorMap field_generators_;
@@ -218,7 +218,6 @@ class MessageGenerator {
std::vector<const FieldDescriptor *> optimized_order_;
std::vector<int> has_bit_indices_;
int max_has_bit_index_;
- 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_;
@@ -227,9 +226,10 @@ class MessageGenerator {
// table_driven_ indicates the generated message uses table-driven parsing.
bool table_driven_;
- int index_in_file_messages_;
+ google::protobuf::scoped_ptr<MessageLayoutHelper> message_layout_helper_;
SCCAnalyzer* scc_analyzer_;
+ string scc_name_;
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 da4c3950..5888f51a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -45,13 +45,42 @@ namespace cpp {
namespace {
+// When we are generating code for implicit weak fields, we need to insert some
+// additional casts. These functions return the casted expression if
+// implicit_weak_field is true but otherwise return the original expression.
+// Ordinarily a static_cast is enough to cast google::protobuf::MessageLite* to a class
+// deriving from it, but we need a reinterpret_cast in cases where the generated
+// message is forward-declared but its full definition is not visible.
+string StaticCast(const string& type, const string& expression,
+ bool implicit_weak_field) {
+ if (implicit_weak_field) {
+ return "static_cast< " + type + " >(" + expression + ")";
+ } else {
+ return expression;
+ }
+}
+
+string ReinterpretCast(const string& type, const string& expression,
+ bool implicit_weak_field) {
+ if (implicit_weak_field) {
+ return "reinterpret_cast< " + type + " >(" + expression + ")";
+ } else {
+ return expression;
+ }
+}
+
void SetMessageVariables(const FieldDescriptor* descriptor,
std::map<string, string>* variables,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
+ (*variables)["casted_member"] =
+ StaticCast((*variables)["type"] + "*", (*variables)["name"] + "_",
+ IsImplicitWeakField(descriptor, options));
(*variables)["type_default_instance"] =
DefaultInstanceName(descriptor->message_type());
+ (*variables)["type_reference_function"] =
+ ReferenceFunctionName(descriptor->message_type());
if (descriptor->options().weak() || !descriptor->containing_oneof()) {
(*variables)["non_null_ptr_to_name"] =
StrCat("this->", (*variables)["name"], "_");
@@ -85,7 +114,8 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: FieldGenerator(options),
descriptor_(descriptor),
- dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
+ dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
+ implicit_weak_field_(IsImplicitWeakField(descriptor, options)) {
SetMessageVariables(descriptor, &variables_, options);
}
@@ -93,7 +123,11 @@ MessageFieldGenerator::~MessageFieldGenerator() {}
void MessageFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
- printer->Print(variables_, "$type$* $name$_;\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables_, "google::protobuf::MessageLite* $name$_;\n");
+ } else {
+ printer->Print(variables_, "$type$* $name$_;\n");
+ }
}
void MessageFieldGenerator::
@@ -108,7 +142,11 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const {
if (!dependent_field_) {
return;
}
- // Arena manipulation code is out-of-line in the derived message class.
+ // Arena manipulation code is out-of-line in the derived message class. The
+ // one exception is unsafe_arena_release_; this method has to be inline so
+ // that when the implicit weak field optimization is enabled, the method does
+ // not introduce a strong dependency on the submessage type unless the
+ // accessor actually gets called somewhere.
printer->Print(variables_,
"$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
@@ -118,14 +156,22 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const {
"$deprecated_attr$void ${$set_allocated_$name$$}$"
"($type$* $name$);\n");
printer->Annotate("{", "}", descriptor_);
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ variables_,
+ "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ }
}
void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- "private:\n"
- "void _slow_mutable_$name$();\n");
+ "private:\n");
+ if (!implicit_weak_field_) {
+ printer->Print(variables_, "void _slow_mutable_$name$();\n");
+ }
if (SupportsArenas(descriptor_->message_type())) {
printer->Print(variables_,
"void _slow_set_allocated_$name$(\n"
@@ -135,6 +181,16 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"$type$* _slow_$release_name$();\n"
"public:\n");
}
+ if (implicit_weak_field_) {
+ // These private accessors are used by MergeFrom and
+ // MergePartialFromCodedStream, and their purpose is to provide access to
+ // the field without creating a strong dependency on the message type.
+ printer->Print(variables_,
+ "private:\n"
+ "const google::protobuf::MessageLite& _internal_$name$() const;\n"
+ "google::protobuf::MessageLite* _internal_mutable_$name$();\n"
+ "public:\n");
+ }
GenerateGetterDeclaration(printer);
if (!dependent_field_) {
printer->Print(variables_,
@@ -146,12 +202,14 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"$deprecated_attr$void ${$set_allocated_$name$$}$"
"($type$* $name$);\n");
printer->Annotate("{", "}", descriptor_);
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ variables_,
+ "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ }
}
if (SupportsArenas(descriptor_)) {
- printer->Print(
- variables_,
- "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n");
- printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
"$deprecated_attr$void "
"${$unsafe_arena_set_allocated_$name$$}$(\n"
@@ -162,9 +220,39 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
io::Printer* printer) const {
- if (SupportsArenas(descriptor_)) {
+ if (implicit_weak_field_) {
printer->Print(variables_,
- "void $classname$::_slow_mutable_$name$() {\n");
+ "const google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n"
+ " if ($name$_ != NULL) {\n"
+ " return *$name$_;\n"
+ " } else if (&$type_default_instance$ != NULL) {\n"
+ " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &$type_default_instance$);\n"
+ " } else {\n"
+ " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &::google::protobuf::internal::implicit_weak_message_default_instance);\n"
+ " }\n"
+ "}\n");
+ }
+ if (SupportsArenas(descriptor_)) {
+ if (implicit_weak_field_) {
+ printer->Print(variables_,
+ "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " if ($name$_ == NULL) {\n"
+ " if (&$type_default_instance$ == NULL) {\n"
+ " $name$_ = ::google::protobuf::Arena::CreateMessage<\n"
+ " ::google::protobuf::internal::ImplicitWeakMessage>(\n"
+ " GetArenaNoVirtual());\n"
+ " } else {\n"
+ " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &$type_default_instance$)->New(GetArenaNoVirtual());\n"
+ " }\n"
+ " }\n"
+ " return $name$_;\n");
+ } else {
+ printer->Print(variables_,
+ "void $classname$::_slow_mutable_$name$() {\n");
if (SupportsArenas(descriptor_->message_type())) {
printer->Print(variables_,
" $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
@@ -174,23 +262,27 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
" $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
" GetArenaNoVirtual());\n");
}
+ }
printer->Print(variables_,
"}\n"
"$type$* $classname$::_slow_$release_name$() {\n"
" if ($name$_ == NULL) {\n"
" return NULL;\n"
- " } else {\n"
- " $type$* temp = new $type$(*$name$_);\n"
- " $name$_ = NULL;\n"
- " return temp;\n"
+ " } else {\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables_,
+ " google::protobuf::MessageLite* temp = $name$_->New();\n"
+ " temp->CheckTypeAndMergeFrom(*$name$_);\n");
+ } else {
+ printer->Print(variables_,
+ " $type$* temp = new $type$(*$name$_);\n");
+ }
+ printer->Print(variables_, " $name$_ = NULL;\n");
+ printer->Print(
+ " return $result$;\n", "result",
+ StaticCast(variables_.at("type") + "*", "temp", implicit_weak_field_));
+ printer->Print(variables_,
" }\n"
- "}\n"
- "$type$* $classname$::unsafe_arena_release_$name$() {\n"
- " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
- " $clear_hasbit$\n"
- " $type$* temp = $name$_;\n"
- " $name$_ = NULL;\n"
- " return temp;\n"
"}\n");
if (SupportsArenas(descriptor_->message_type())) {
// NOTE: the same logic is mirrored in weak_message_field.cc. Any
@@ -202,12 +294,23 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
" ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n"
" message_arena->Own(*$name$);\n"
" } else if (message_arena !=\n"
- " ::google::protobuf::Arena::GetArena(*$name$)) {\n"
- " $type$* new_$name$ = \n"
- " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
- " message_arena);\n"
- " new_$name$->CopyFrom(**$name$);\n"
- " *$name$ = new_$name$;\n"
+ " ::google::protobuf::Arena::GetArena(*$name$)) {\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables_,
+ " google::protobuf::MessageLite* new_$name$ =\n"
+ " reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &$type_default_instance$)->New(GetArenaNoVirtual());\n"
+ " new_$name$->CheckTypeAndMergeFrom(**$name$);\n"
+ " *$name$ = static_cast< $type$* >(new_$name$);\n");
+ } else {
+ printer->Print(variables_,
+ " $type$* new_$name$ =\n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " message_arena);\n"
+ " new_$name$->CopyFrom(**$name$);\n"
+ " *$name$ = new_$name$;\n");
+ }
+ printer->Print(variables_,
" }\n"
"}\n");
}
@@ -228,6 +331,20 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
":$full_name$)\n"
"}\n");
+ } else if (implicit_weak_field_) {
+ printer->Print(variables_,
+ "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " if ($name$_ == NULL) {\n"
+ " if (&$type_default_instance$ == NULL) {\n"
+ " $name$_ = new ::google::protobuf::internal::ImplicitWeakMessage;\n"
+ " } else {\n"
+ " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &$type_default_instance$)->New();\n"
+ " }\n"
+ " }\n"
+ " return $name$_;\n"
+ "}\n");
}
}
@@ -243,6 +360,10 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
variables["dependent_classname"] =
DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
variables["this_message"] = DependentBaseDownCast();
+ variables["casted_reference"] =
+ ReinterpretCast(variables["dependent_typename"] + "*&",
+ variables["this_message"] + variables["name"] + "_",
+ implicit_weak_field_);
if (!variables["set_hasbit"].empty()) {
variables["set_hasbit"] =
variables["this_message"] + variables["set_hasbit"];
@@ -255,19 +376,39 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
if (SupportsArenas(descriptor_)) {
printer->Print(variables,
"template <class T>\n"
- "inline $type$* $dependent_classname$::mutable_$name$() {\n"
+ "inline $type$* $dependent_classname$::mutable_$name$() {\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
" $set_hasbit$\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
- " if ($name$_ == NULL) {\n"
- " $this_message$_slow_mutable_$name$();\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
+ " if ($name$_ == NULL) {\n");
+ if (implicit_weak_field_) {
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables,
+ " $name$_ = reinterpret_cast<$dependent_typename$*>(\n"
+ " reinterpret_cast<const google::protobuf::MessageLite*>(\n"
+ " &$type_default_instance$)->New(\n"
+ " $this_message$GetArenaNoVirtual()));\n");
+ }
+ } else {
+ printer->Print(variables,
+ " $this_message$_slow_mutable_$name$();\n");
+ }
+ printer->Print(variables,
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
" return $name$_;\n"
"}\n"
"template <class T>\n"
"inline $type$* $dependent_classname$::$release_name$() {\n"
- " // @@protoc_insertion_point(field_release:$full_name$)\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+ " // @@protoc_insertion_point(field_release:$full_name$)\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
" $clear_hasbit$\n"
" if ($this_message$GetArenaNoVirtual() != NULL) {\n"
" return $this_message$_slow_$release_name$();\n"
@@ -281,7 +422,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
"inline void $dependent_classname$::"
"set_allocated_$name$($type$* $name$) {\n"
" ::google::protobuf::Arena* message_arena = $this_message$GetArenaNoVirtual();\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
" if (message_arena == NULL) {\n"
" delete $name$_;\n"
" }\n"
@@ -311,13 +452,27 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
" }\n"
// TODO(dlj): move insertion points to message class.
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "template <class T>\n"
+ "inline $type$* $dependent_classname$::unsafe_arena_release_$name$() {\n"
+ " // @@protoc_insertion_point("
+ "field_unsafe_arena_release:$full_name$)\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
+ " $clear_hasbit$\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
+ " $dependent_typename$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
"}\n");
} else {
printer->Print(variables,
"template <class T>\n"
"inline $type$* $dependent_classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
" if ($name$_ == NULL) {\n"
" $name$_ = new $dependent_typename$;\n"
" }\n"
@@ -326,9 +481,13 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
"}\n"
"template <class T>\n"
"inline $type$* $dependent_classname$::$release_name$() {\n"
- " // @@protoc_insertion_point(field_release:$full_name$)\n"
+ " // @@protoc_insertion_point(field_release:$full_name$)\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
" $clear_hasbit$\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
" $dependent_typename$* temp = $name$_;\n"
" $name$_ = NULL;\n"
" return temp;\n"
@@ -336,7 +495,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
"template <class T>\n"
"inline void $dependent_classname$::"
"set_allocated_$name$($type$* $name$) {\n"
- " $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+ " $dependent_typename$*& $name$_ = $casted_reference$;\n"
" delete $name$_;\n");
if (SupportsArenas(descriptor_->message_type())) {
@@ -366,9 +525,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const {
std::map<string, string> variables(variables_);
variables["inline"] = is_inline ? "inline " : "";
+ variables["const_member"] = ReinterpretCast(
+ "const " + variables["type"] + "*", variables["name"] + "_",
+ implicit_weak_field_);
printer->Print(variables,
- "$inline$const $type$& $classname$::$name$() const {\n"
- " const $type$* p = $name$_;\n"
+ "$inline$const $type$& $classname$::$name$() const {\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
+ " const $type$* p = $const_member$;\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n"
" &$type_default_instance$);\n"
@@ -381,11 +547,18 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"$inline$"
"$type$* $classname$::mutable_$name$() {\n"
" $set_hasbit$\n"
- " if ($name$_ == NULL) {\n"
- " _slow_mutable_$name$();\n"
+ " if ($name$_ == NULL) {\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables,
+ " _internal_mutable_$name$();\n");
+ } else {
+ printer->Print(variables,
+ " _slow_mutable_$name$();\n");
+ }
+ printer->Print(variables,
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
- " return $name$_;\n"
+ " return $casted_member$;\n"
"}\n"
"$inline$"
"$type$* $classname$::$release_name$() {\n"
@@ -394,7 +567,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" if (GetArenaNoVirtual() != NULL) {\n"
" return _slow_$release_name$();\n"
" } else {\n"
- " $type$* temp = $name$_;\n"
+ " $type$* temp = $casted_member$;\n"
" $name$_ = NULL;\n"
" return temp;\n"
" }\n"
@@ -429,6 +602,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" $clear_hasbit$\n"
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "$inline$"
+ "$type$* $classname$::unsafe_arena_release_$name$() {\n"
+ " // @@protoc_insertion_point("
+ "field_unsafe_arena_release:$full_name$)\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables, " $type_reference_function$();\n");
+ }
+ printer->Print(variables,
+ " $clear_hasbit$\n"
+ " $type$* temp = $casted_member$;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
"}\n");
} else {
printer->Print(variables,
@@ -439,13 +625,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" $name$_ = new $type$;\n"
" }\n"
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
- " return $name$_;\n"
+ " return $casted_member$;\n"
"}\n"
"$inline$"
"$type$* $classname$::$release_name$() {\n"
" // @@protoc_insertion_point(field_release:$full_name$)\n"
" $clear_hasbit$\n"
- " $type$* temp = $name$_;\n"
+ " $type$* temp = $casted_member$;\n"
" $name$_ = NULL;\n"
" return temp;\n"
"}\n"
@@ -485,6 +671,9 @@ GenerateClearingCode(io::Printer* printer) const {
"if ($this_message$GetArenaNoVirtual() == NULL && "
"$this_message$$name$_ != NULL) delete $this_message$$name$_;\n"
"$this_message$$name$_ = NULL;\n");
+ } else if (implicit_weak_field_) {
+ printer->Print(variables,
+ "if ($this_message$$name$_ != NULL) $this_message$$name$_->Clear();\n");
} else {
printer->Print(variables,
"if ($this_message$$name$_ != NULL) $this_message$$name$_->"
@@ -502,6 +691,10 @@ GenerateMessageClearingCode(io::Printer* printer) const {
" delete $name$_;\n"
"}\n"
"$name$_ = NULL;\n");
+ } else if (implicit_weak_field_) {
+ printer->Print(variables_,
+ "GOOGLE_DCHECK($name$_ != NULL);\n"
+ "$name$_->Clear();\n");
} else {
printer->Print(variables_,
"GOOGLE_DCHECK($name$_ != NULL);\n"
@@ -511,8 +704,14 @@ GenerateMessageClearingCode(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "mutable_$name$()->$type$::MergeFrom(from.$name$());\n");
+ if (implicit_weak_field_) {
+ printer->Print(variables_,
+ "_internal_mutable_$name$()->CheckTypeAndMergeFrom(\n"
+ " from._internal_$name$());\n");
+ } else {
+ printer->Print(variables_,
+ "mutable_$name$()->$type$::MergeFrom(from.$name$());\n");
+ }
}
void MessageFieldGenerator::
@@ -557,17 +756,24 @@ GenerateCopyConstructorCode(io::Printer* printer) const {
// 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");
+ string new_expression = (implicit_weak_field_ ? "from.$name$_->New()"
+ : "new $type$(*from.$name$_)");
+ string output =
+ "if (from.has_$name$()) {\n"
+ " $name$_ = " + new_expression + ";\n"
+ "} else {\n"
+ " $name$_ = NULL;\n"
+ "}\n";
+ printer->Print(variables_, output.c_str());
}
void MessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
- if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+ if (implicit_weak_field_) {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n"
+ " input, _internal_mutable_$name$()));\n");
+ } else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
" input, mutable_$name$()));\n");
@@ -595,9 +801,11 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
- printer->Print(variables_,
+ std::map<string, string> variables = variables_;
+ variables["no_virtual"] = (implicit_weak_field_ ? "" : "NoVirtual");
+ printer->Print(variables,
"total_size += $tag_size$ +\n"
- " ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
+ " ::google::protobuf::internal::WireFormatLite::$declared_type$Size$no_virtual$(\n"
" *$non_null_ptr_to_name$);\n");
}
@@ -771,13 +979,15 @@ void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions(
" }\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n"
- "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n"
+ "$tmpl$"
+ "$inline$"
+ "$type$* $dependent_classname$::unsafe_arena_release_$name$() {\n"
" // @@protoc_insertion_point(field_unsafe_arena_release"
":$full_name$)\n"
- " if (has_$name$()) {\n"
- " clear_has_$oneof_name$();\n"
- " $type$* temp = $oneof_prefix$$name$_;\n"
- " $oneof_prefix$$name$_ = NULL;\n"
+ " if ($this_message$has_$name$()) {\n"
+ " $this_message$clear_has_$oneof_name$();\n"
+ " $dependent_typename$* temp = $this_message$$oneof_prefix$$name$_;\n"
+ " $this_message$$oneof_prefix$$name$_ = NULL;\n"
" return temp;\n"
" } else {\n"
" return NULL;\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index cd9737f0..14698992 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -44,6 +44,8 @@ namespace protobuf {
namespace compiler {
namespace cpp {
+bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options);
+
class MessageFieldGenerator : public FieldGenerator {
public:
MessageFieldGenerator(const FieldDescriptor* descriptor,
@@ -78,6 +80,7 @@ class MessageFieldGenerator : public FieldGenerator {
const FieldDescriptor* descriptor_;
const bool dependent_field_;
+ const bool implicit_weak_field_;
std::map<string, string> variables_;
private:
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h
new file mode 100644
index 00000000..d502a6f0
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h
@@ -0,0 +1,61 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: seongkim@google.com (Seong Beom Kim)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
+
+#include <google/protobuf/compiler/cpp/cpp_options.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Provides an abstract interface to optimize message layout
+// by rearranging the fields of a message.
+class MessageLayoutHelper {
+ public:
+ virtual ~MessageLayoutHelper() {}
+
+ virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
+ const Options& options) = 0;
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 04338083..4a29ad0e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -39,6 +39,8 @@
namespace google {
namespace protobuf {
namespace compiler {
+class AccessInfoMap;
+
namespace cpp {
// Generator options (see generator.cc for a description of each):
@@ -50,7 +52,9 @@ struct Options {
annotate_headers(false),
enforce_lite(false),
table_driven_parsing(false),
- table_driven_serialization(false) {}
+ table_driven_serialization(false),
+ lite_implicit_weak_fields(false),
+ access_info_map(NULL) {}
string dllexport_decl;
bool safe_boundary_check;
@@ -60,8 +64,10 @@ struct Options {
bool enforce_lite;
bool table_driven_parsing;
bool table_driven_serialization;
+ bool lite_implicit_weak_fields;
string annotation_pragma_name;
string annotation_guard_name;
+ const AccessInfoMap* access_info_map;
};
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
new file mode 100644
index 00000000..e9303865
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
@@ -0,0 +1,220 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h>
+
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+namespace {
+
+// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of
+// fields that are grouped together because they have compatible alignment, and
+// a preferred location in the final field ordering.
+class FieldGroup {
+ public:
+ FieldGroup() : preferred_location_(0) {}
+
+ // A group with a single field.
+ FieldGroup(float preferred_location, const FieldDescriptor* field)
+ : preferred_location_(preferred_location), fields_(1, field) {}
+
+ // Append the fields in 'other' to this group.
+ void Append(const FieldGroup& other) {
+ if (other.fields_.empty()) {
+ return;
+ }
+ // Preferred location is the average among all the fields, so we weight by
+ // the number of fields on each FieldGroup object.
+ preferred_location_ = (preferred_location_ * fields_.size() +
+ (other.preferred_location_ * other.fields_.size())) /
+ (fields_.size() + other.fields_.size());
+ fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
+ }
+
+ void SetPreferredLocation(float location) { preferred_location_ = location; }
+ const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
+
+ // FieldGroup objects sort by their preferred location.
+ bool operator<(const FieldGroup& other) const {
+ return preferred_location_ < other.preferred_location_;
+ }
+
+ private:
+ // "preferred_location_" is an estimate of where this group should go in the
+ // final list of fields. We compute this by taking the average index of each
+ // field in this group in the original ordering of fields. This is very
+ // approximate, but should put this group close to where its member fields
+ // originally went.
+ float preferred_location_;
+ std::vector<const FieldDescriptor*> fields_;
+ // We rely on the default copy constructor and operator= so this type can be
+ // used in a vector.
+};
+
+} // namespace
+
+// Reorder 'fields' so that if the fields are output into a c++ class in the new
+// order, fields of similar family (see below) are together and within each
+// family, alignment padding is minimized.
+//
+// We try to do this while keeping each field as close as possible to its field
+// number order so that we don't reduce cache locality much for function that
+// access each field in order. Originally, OptimizePadding used declaration
+// order for its decisions, but generated code minus the serializer/parsers uses
+// the output of OptimizePadding as well (stored in
+// MessageGenerator::optimized_order_). Since the serializers use field number
+// order, we use that as a tie-breaker.
+//
+// We classify each field into a particular "family" of fields, that we perform
+// the same operation on in our generated functions.
+//
+// REPEATED is placed first, as the C++ compiler automatically initializes
+// these fields in layout order.
+//
+// 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), which allows them to be
+// memset.
+//
+// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
+//
+// OTHER these fields are initialized one-by-one.
+void PaddingOptimizer::OptimizeLayout(
+ 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 = 3,
+ ZERO_INITIALIZABLE = 4,
+ OTHER = 5,
+ kMaxFamily
+ };
+
+ // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
+ 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];
+
+ Family f = OTHER;
+ if (field->is_repeated()) {
+ f = REPEATED;
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ f = STRING;
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ f = MESSAGE;
+
+ } else if (CanInitializeByZeroing(field)) {
+ f = ZERO_INITIALIZABLE;
+ }
+
+ const int j = field->number();
+ switch (EstimateAlignmentSize(field)) {
+ case 1:
+ aligned_to_1[f].push_back(FieldGroup(j, field));
+ break;
+ case 4:
+ aligned_to_4[f].push_back(FieldGroup(j, field));
+ break;
+ case 8:
+ aligned_to_8[f].push_back(FieldGroup(j, field));
+ break;
+ default:
+ GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field)
+ << "for a field " << field->full_name() << ".";
+ }
+ }
+
+ // For each family, group fields to optimize padding.
+ for (int f = 0; f < kMaxFamily; f++) {
+ // Now group fields aligned to 1 byte into sets of 4, and treat those like a
+ // single field aligned to 4 bytes.
+ for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
+ FieldGroup field_group;
+ for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
+ field_group.Append(aligned_to_1[f][j]);
+ }
+ aligned_to_4[f].push_back(field_group);
+ }
+ // Sort by preferred location to keep fields as close to their field number
+ // order as possible. Using stable_sort ensures that the output is
+ // consistent across runs.
+ std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
+
+ // Now group fields aligned to 4 bytes (or the 4-field groups created above)
+ // into pairs, and treat those like a single field aligned to 8 bytes.
+ for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
+ FieldGroup field_group;
+ for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
+ field_group.Append(aligned_to_4[f][j]);
+ }
+ if (i == aligned_to_4[f].size() - 1) {
+ if (f == OTHER) {
+ // Move incomplete 4-byte block to the beginning. This is done to
+ // pair with the (possible) leftover blocks from the
+ // ZERO_INITIALIZABLE family.
+ field_group.SetPreferredLocation(-1);
+ } else {
+ // Move incomplete 4-byte block to the end.
+ field_group.SetPreferredLocation(fields->size() + 1);
+ }
+ }
+ aligned_to_8[f].push_back(field_group);
+ }
+ // Sort by preferred location.
+ std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
+ }
+
+ // Now pull out all the FieldDescriptors in order.
+ fields->clear();
+ for (int f = 0; f < kMaxFamily; ++f) {
+ for (int i = 0; i < aligned_to_8[f].size(); ++i) {
+ fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(),
+ aligned_to_8[f][i].fields().end());
+ }
+ }
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h
new file mode 100644
index 00000000..9641ba40
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: seongkim@google.com (Seong Beom Kim)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
+
+#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Rearranges the fields of a message to minimize padding.
+// Fields are grouped by the type and the size.
+// For example, grouping four boolean fields and one int32
+// field results in zero padding overhead. See OptimizeLayout's
+// comment for details.
+class PaddingOptimizer : public MessageLayoutHelper {
+ public:
+ PaddingOptimizer() {}
+ ~PaddingOptimizer() {}
+
+ void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
+ const Options& options);
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index b05fcc4e..67cfc405 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -245,9 +245,8 @@ GenerateSwappingCode(io::Printer* printer) const {
void PrimitiveOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
- printer->Print(
- variables_,
- "_$classname$_default_instance_.$name$_ = $default$;\n");
+ printer->Print(variables_,
+ "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n");
}
void PrimitiveOneofFieldGenerator::
@@ -433,7 +432,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
- " static_cast< ::google::protobuf::uint32>(\n"
+ " static_cast< ::google::protobuf::int32>(\n"
" _$name$_cached_byte_size_), target);\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoTagToArray(this->$name$_, target);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index fec13b6d..8e675751 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -58,8 +58,8 @@ void SetStringVariables(const FieldDescriptor* descriptor,
(*variables)["default_variable"] =
descriptor->default_value_string().empty()
? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
- : "&" + (*variables)["classname"] + "::" + default_variable_string +
- ".get()";
+ : "&" + Namespace(descriptor) + "::" + (*variables)["classname"] +
+ "::" + default_variable_string + ".get()";
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
(*variables)["null_check"] = "GOOGLE_DCHECK(value != NULL);\n";
@@ -71,6 +71,9 @@ void SetStringVariables(const FieldDescriptor* descriptor,
(*variables)["full_name"] = descriptor->full_name();
(*variables)["string_piece"] = "::std::string";
+
+ (*variables)["lite"] =
+ HasDescriptorMethods(descriptor->file(), options) ? "" : "Lite";
}
} // namespace
@@ -79,7 +82,8 @@ void SetStringVariables(const FieldDescriptor* descriptor,
StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
- : FieldGenerator(options), descriptor_(descriptor) {
+ : FieldGenerator(options), descriptor_(descriptor),
+ lite_(!HasDescriptorMethods(descriptor->file(), options)) {
SetStringVariables(descriptor, &variables_, options);
}
@@ -207,13 +211,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"}\n"
"$inline$void $classname$::set_$name$(const ::std::string& value) {\n"
" $set_hasbit$\n"
- " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
+ " $name$_.Set$lite$($default_variable$, value, GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
"#if LANG_CXX11\n"
"$inline$void $classname$::set_$name$(::std::string&& value) {\n"
" $set_hasbit$\n"
- " $name$_.Set(\n"
+ " $name$_.Set$lite$(\n"
" $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
"}\n"
@@ -221,7 +225,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"$inline$void $classname$::set_$name$(const char* value) {\n"
" $null_check$"
" $set_hasbit$\n"
- " $name$_.Set($default_variable$, $string_piece$(value),\n"
+ " $name$_.Set$lite$($default_variable$, $string_piece$(value),\n"
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
@@ -229,7 +233,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"void $classname$::set_$name$(const $pointer_type$* value,\n"
" size_t size) {\n"
" $set_hasbit$\n"
- " $name$_.Set($default_variable$, $string_piece$(\n"
+ " $name$_.Set$lite$($default_variable$, $string_piece$(\n"
" reinterpret_cast<const char*>(value), size), "
"GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
@@ -453,7 +457,7 @@ GenerateCopyConstructorCode(io::Printer* printer) const {
if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
// TODO(gpike): improve this
printer->Print(variables_,
- "$name$_.Set($default_variable$, from.$name$(),\n"
+ "$name$_.Set$lite$($default_variable$, from.$name$(),\n"
" GetArenaNoVirtual());\n");
} else {
printer->Print(variables_,
@@ -480,13 +484,14 @@ GenerateDestructorCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateDefaultInstanceAllocator(io::Printer* printer) const {
if (!descriptor_->default_value_string().empty()) {
- printer->Print(variables_,
- "$classname$::$default_variable_name$.DefaultConstruct();\n"
- "*$classname$::$default_variable_name$.get_mutable() = "
- "::std::string($default$, $default_length$);\n"
- "::google::protobuf::internal::OnShutdownDestroyString(\n"
- " $classname$::$default_variable_name$.get_mutable());\n"
- );
+ printer->Print(
+ variables_,
+ "$ns$::$classname$::$default_variable_name$.DefaultConstruct();\n"
+ "*$ns$::$classname$::$default_variable_name$.get_mutable() = "
+ "::std::string($default$, $default_length$);\n"
+ "::google::protobuf::internal::OnShutdownDestroyString(\n"
+ " $ns$::$classname$::$default_variable_name$.get_mutable());\n"
+ );
}
}
@@ -572,7 +577,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" set_has_$name$();\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
- " $oneof_prefix$$name$_.Set($default_variable$, value,\n"
+ " $oneof_prefix$$name$_.Set$lite$($default_variable$, value,\n"
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
@@ -584,7 +589,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" set_has_$name$();\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
- " $oneof_prefix$$name$_.Set(\n"
+ " $oneof_prefix$$name$_.Set$lite$(\n"
" $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
"}\n"
@@ -596,7 +601,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" set_has_$name$();\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
- " $oneof_prefix$$name$_.Set($default_variable$,\n"
+ " $oneof_prefix$$name$_.Set$lite$($default_variable$,\n"
" $string_piece$(value), GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
@@ -608,7 +613,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" set_has_$name$();\n"
" $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
" }\n"
- " $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n"
+ " $oneof_prefix$$name$_.Set$lite$(\n"
+ " $default_variable$, $string_piece$(\n"
" reinterpret_cast<const char*>(value), size),\n"
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
@@ -806,7 +812,7 @@ void StringOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(
variables_,
- "_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n"
+ "$ns$::_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n"
" $default_variable$);\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 531252b0..933f3c6b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -73,6 +73,7 @@ class StringFieldGenerator : public FieldGenerator {
protected:
const FieldDescriptor* descriptor_;
std::map<string, string> variables_;
+ const bool lite_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 4e25b2ea..7fe98759 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -151,6 +151,10 @@ enum ConflictingEnum { // NO_PROTO3
message DummyMessage {}
+// Message names that could conflict.
+message Shutdown {}
+message TableStruct {}
+
service TestConflictingMethodNames {
rpc Closure(DummyMessage) returns (DummyMessage);
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index fdde771b..61cc32a4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -744,21 +744,6 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) {
TestUtil::ExpectAllFieldsSet(message1);
}
-#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), "pb[.]cc.*Check failed:");
- EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)),
- "pb[.]cc.*Check failed:");
-}
-
-#endif // NDEBUG
-#endif // PROTOBUF_HAS_DEATH_TEST
-#endif // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI
// Test the generated SerializeWithCachedSizesToArray(),
TEST(GeneratedMessageTest, SerializationToArray) {