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_bootstrap_unittest.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc16
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc154
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc103
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h67
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc79
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc911
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h33
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc20
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc19
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc56
17 files changed, 1149 insertions, 354 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index bf4e5831..fce58c02 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -46,12 +46,11 @@
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/testing/file.h>
@@ -126,9 +125,12 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) {
importer.Import("google/protobuf/descriptor.proto");
const FileDescriptor* plugin_proto_file =
importer.Import("google/protobuf/compiler/plugin.proto");
+ const FileDescriptor* profile_proto_file =
+ importer.Import("google/protobuf/compiler/profile.proto");
EXPECT_EQ("", error_collector.text_);
ASSERT_TRUE(proto_file != NULL);
ASSERT_TRUE(plugin_proto_file != NULL);
+ ASSERT_TRUE(profile_proto_file != NULL);
CppGenerator generator;
MockGeneratorContext context;
@@ -139,6 +141,8 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) {
parameter = "dllexport_decl=LIBPROTOC_EXPORT";
ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter,
&context, &error));
+ ASSERT_TRUE(generator.Generate(profile_proto_file, parameter,
+ &context, &error));
context.ExpectFileMatches("google/protobuf/descriptor.pb.h",
"google/protobuf/descriptor.pb.h");
@@ -148,6 +152,10 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) {
"google/protobuf/compiler/plugin.pb.h");
context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc",
"google/protobuf/compiler/plugin.pb.cc");
+ context.ExpectFileMatches("google/protobuf/compiler/profile.pb.h",
+ "google/protobuf/compiler/profile.pb.h");
+ context.ExpectFileMatches("google/protobuf/compiler/profile.pb.cc",
+ "google/protobuf/compiler/profile.pb.cc");
}
} // namespace
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index e4b17a98..c15be942 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -318,7 +318,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedEnumFieldGenerator::
@@ -461,20 +461,14 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
" _$name$_cached_byte_size_, target);\n"
- "}\n");
- }
- printer->Print(variables_,
- "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
- if (descriptor_->is_packed()) {
- printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
- " this->$name$(i), target);\n");
+ " this->$name$_, target);\n"
+ "}\n");
} else {
printer->Print(variables_,
- " target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
- " $number$, this->$name$(i), target);\n");
+ "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
+ " $number$, this->$name$_, target);\n");
}
- printer->Print("}\n");
}
void RepeatedEnumFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index f2e013c0..83e68c12 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -39,6 +39,7 @@
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <set>
+#include <vector>
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_service.h>
@@ -67,7 +68,7 @@ bool IsMacroName(const string& name) {
return false;
}
-void CollectMacroNames(const Descriptor* message, vector<string>* names) {
+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())) {
@@ -79,7 +80,13 @@ void CollectMacroNames(const Descriptor* message, vector<string>* names) {
}
}
-void CollectMacroNames(const FileDescriptor* file, vector<string>* 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);
}
@@ -93,18 +100,19 @@ void CollectMacroNames(const FileDescriptor* file, vector<string>* names) {
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() ]),
+ new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
enum_generators_owner_(
- new google::protobuf::scoped_ptr<EnumGenerator>[ file->enum_type_count() ]),
+ new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]),
service_generators_owner_(
- new google::protobuf::scoped_ptr<ServiceGenerator>[ file->service_count() ]),
+ new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]),
extension_generators_owner_(
- new google::protobuf::scoped_ptr<ExtensionGenerator>[ file->extension_count() ]) {
+ 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));
+ new MessageGenerator(file->message_type(i), options, &scc_analyzer_));
message_generators_owner_[i]->Flatten(&message_generators_);
}
@@ -137,7 +145,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
FileGenerator::~FileGenerator() {}
void FileGenerator::GenerateMacroUndefs(io::Printer* printer) {
- vector<string> names_to_undef;
+ std::vector<string> names_to_undef;
CollectMacroNames(file_, &names_to_undef);
for (int i = 0; i < names_to_undef.size(); ++i) {
printer->Print(
@@ -241,6 +249,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer,
} else {
GenerateLibraryIncludes(printer);
}
+
GenerateDependencyIncludes(printer);
GenerateMetadataPragma(printer, info_path);
@@ -327,11 +336,17 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
GenerateNamespaceOpeners(printer);
for (int i = 0; i < message_generators_.size(); i++) {
- if (IsMapEntryMessage(message_generators_[i]->descriptor_)) continue;
+ string parent;
+ if (IsMapEntryMessage(message_generators_[i]->descriptor_)) {
+ parent = ClassName(message_generators_[i]->descriptor_->containing_type(),
+ false) +
+ "::";
+ }
printer->Print(
"class $classname$DefaultTypeInternal : "
- "public ::google::protobuf::internal::ExplicitlyConstructed<$classname$> {\n",
- "classname", message_generators_[i]->classname_);
+ "public ::google::protobuf::internal::ExplicitlyConstructed<$parent$$classname$> "
+ "{\n",
+ "parent", parent, "classname", message_generators_[i]->classname_);
printer->Indent();
message_generators_[i]->GenerateExtraDefaultFields(printer);
printer->Outdent();
@@ -340,9 +355,6 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"classname", message_generators_[i]->classname_);
}
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->index_in_metadata_ = i;
- }
for (int i = 0; i < enum_generators_.size(); i++) {
enum_generators_[i]->index_in_metadata_ = i;
}
@@ -530,6 +542,70 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// 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[] = {\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[] = {\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[] = {\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 (HasDescriptorMethods(file_, options_)) {
if (!message_generators_.empty()) {
printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] = {\n");
@@ -560,8 +636,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Indent();
for (int i = 0; i < message_generators_.size(); i++) {
const Descriptor* descriptor = message_generators_[i]->descriptor_;
- if (IsMapEntryMessage(descriptor)) continue;
-
printer->Print(
"reinterpret_cast<const "
"::google::protobuf::Message*>(&_$classname$_default_instance_),\n",
@@ -600,7 +674,31 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
" AssignDescriptors(\n"
" \"$filename$\", schemas, file_default_instances, "
"TableStruct::offsets, factory,\n"
- " $metadata$, $enum_descriptors$, $service_descriptors$);\n"
+ " $metadata$, $enum_descriptors$, $service_descriptors$);\n",
+ "filename", file_->name(), "metadata",
+ !message_generators_.empty() ? "file_level_metadata" : "NULL",
+ "enum_descriptors",
+ !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL",
+ "service_descriptors",
+ HasGenericServices(file_, options_) && file_->service_count() > 0
+ ? "file_level_service_descriptors"
+ : "NULL",
+ "factory", message_factory);
+ // 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_.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"
"void protobuf_AssignDescriptorsOnce() {\n"
@@ -634,12 +732,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"size", SimpleItoa(message_generators_.size()));
}
- // Map types are treated special
- // TODO(gerbens) find a way to treat maps more like normal messages.
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->GenerateTypeRegistrations(printer);
- }
-
printer->Outdent();
printer->Print(
"}\n"
@@ -902,8 +994,16 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/arena.h>\n"
"#include <google/protobuf/arenastring.h>\n"
- "#include <google/protobuf/generated_message_util.h>\n"
+ "#include <google/protobuf/generated_message_table_driven.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n");
+
+ if (HasDescriptorMethods(file_, options_)) {
+ printer->Print(
"#include <google/protobuf/metadata.h>\n");
+ } else {
+ printer->Print(
+ "#include <google/protobuf/metadata_lite.h>\n");
+ }
if (!message_generators_.empty()) {
if (HasDescriptorMethods(file_, options_)) {
@@ -921,7 +1021,8 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
" // IWYU pragma: export\n");
if (HasMapFields(file_)) {
printer->Print(
- "#include <google/protobuf/map.h>\n");
+ "#include <google/protobuf/map.h>"
+ " // IWYU pragma: export\n");
if (HasDescriptorMethods(file_, options_)) {
printer->Print(
"#include <google/protobuf/map_field_inl.h>\n");
@@ -1001,6 +1102,9 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations(
"namespace $file_namespace$ {\n"
"// Internal implementation detail -- do not call these.\n"
"struct $dllexport_decl$TableStruct {\n"
+ " 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"
// 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.
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index e3fbb96d..e10fe2f3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -43,6 +43,7 @@
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
@@ -145,6 +146,8 @@ class FileGenerator {
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_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 648ab28a..cee31224 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -98,6 +98,8 @@ 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 == "table_driven_parsing") {
+ file_options.table_driven_parsing = true;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 3c4dddc5..9cddba5c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -654,6 +654,109 @@ void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
"VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer);
}
+bool HasWeakFields(const Descriptor* descriptor) {
+ return false;
+}
+
+bool HasWeakFields(const FileDescriptor* file) {
+ return false;
+}
+
+SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
+ // Must not have visited already.
+ GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
+
+ // Mark visited by inserting in map.
+ NodeData& result = cache_[descriptor];
+ // Initialize data structures.
+ result.index = result.lowlink = index_++;
+ stack_.push_back(descriptor);
+
+ // Recurse the fields / nodes in graph
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const Descriptor* child = descriptor->field(i)->message_type();
+ if (child) {
+ if (cache_.count(child) == 0) {
+ // unexplored node
+ NodeData child_data = DFS(child);
+ result.lowlink = std::min(result.lowlink, child_data.lowlink);
+ } else {
+ NodeData child_data = cache_[child];
+ if (child_data.scc == NULL) {
+ // Still in the stack_ so we found a back edge
+ result.lowlink = std::min(result.lowlink, child_data.index);
+ }
+ }
+ }
+ }
+ if (result.index == result.lowlink) {
+ // This is the root of a strongly connected component
+ SCC* scc = CreateSCC();
+ while (true) {
+ const Descriptor* scc_desc = stack_.back();
+ scc->descriptors.push_back(scc_desc);
+ // Remove from stack
+ stack_.pop_back();
+ cache_[scc_desc].scc = scc;
+
+ if (scc_desc == descriptor) break;
+ }
+ }
+ return result;
+}
+
+MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
+ if (analysis_cache_.count(scc)) return analysis_cache_[scc];
+ MessageAnalysis result = MessageAnalysis();
+ for (int i = 0; i < scc->descriptors.size(); i++) {
+ const Descriptor* descriptor = scc->descriptors[i];
+ if (descriptor->extension_range_count() > 0) {
+ result.contains_extension = true;
+ }
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->is_required()) {
+ result.contains_required = true;
+ }
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_BYTES: {
+ if (field->options().ctype() == FieldOptions::CORD) {
+ result.contains_cord = true;
+ }
+ break;
+ }
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE: {
+ const SCC* child = GetSCC(field->message_type());
+ if (child != scc) {
+ MessageAnalysis analysis = GetSCCAnalysis(child);
+ result.contains_cord |= analysis.contains_cord;
+ result.contains_extension |= analysis.contains_extension;
+ if (!ShouldIgnoreRequiredFieldCheck(field, options_)) {
+ result.contains_required |= analysis.contains_required;
+ }
+ } else {
+ // This field points back into the same SCC hence the messages
+ // in the SCC are recursive. Note if SCC contains more than two
+ // nodes it has to be recursive, however this test also works for
+ // a single node that is recursive.
+ result.is_recursive = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ // We deliberately only insert the result here. After we contracted the SCC
+ // in the graph, the graph should be a DAG. Hence we shouldn't need to mark
+ // nodes visited as we can never return to them. By inserting them here
+ // we will go in an infinite loop if the SCC is not correct.
+ return analysis_cache_[scc] = result;
+}
+
} // 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 0f297ec8..a744a865 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -277,6 +277,73 @@ inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
: file->options().optimize_for();
}
+bool HasWeakFields(const Descriptor* desc);
+bool HasWeakFields(const FileDescriptor* desc);
+
+// Returns true if the "required" restriction check should be ignored for the
+// given field.
+inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
+ const Options& options) {
+ return false;
+}
+
+struct SCC {
+ std::vector<const Descriptor*> descriptors;
+};
+
+struct MessageAnalysis {
+ bool is_recursive;
+ bool contains_cord;
+ bool contains_extension;
+ bool contains_required;
+};
+
+// This class is used in FileGenerator, to ensure linear instead of
+// quadratic performance, if we do this per message we would get O(V*(V+E)).
+// Logically this is just only used in message.cc, but in the header for
+// FileGenerator to help share it.
+class LIBPROTOC_EXPORT SCCAnalyzer {
+ public:
+ explicit SCCAnalyzer(const Options& options) : options_(options), index_(0) {}
+ ~SCCAnalyzer() {
+ for (int i = 0; i < garbage_bin_.size(); i++) delete garbage_bin_[i];
+ }
+
+ const SCC* GetSCC(const Descriptor* descriptor) {
+ if (cache_.count(descriptor)) return cache_[descriptor].scc;
+ return DFS(descriptor).scc;
+ }
+
+ MessageAnalysis GetSCCAnalysis(const SCC* scc);
+
+ bool HasRequiredFields(const Descriptor* descriptor) {
+ MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
+ return result.contains_required || result.contains_extension;
+ }
+
+ private:
+ struct NodeData {
+ const SCC* scc; // if null it means its still on the stack
+ int index;
+ int lowlink;
+ };
+
+ Options options_;
+ std::map<const Descriptor*, NodeData> cache_;
+ std::map<const SCC*, MessageAnalysis> analysis_cache_;
+ std::vector<const Descriptor*> stack_;
+ int index_;
+ std::vector<SCC*> garbage_bin_;
+
+ SCC* CreateSCC() {
+ garbage_bin_.push_back(new SCC());
+ return garbage_bin_.back();
+ }
+
+ // Tarjan's Strongly Connected Components algo
+ NodeData DFS(const Descriptor* descriptor);
+};
+
} // 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 b4eaf485..52a3b8b0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -32,6 +32,7 @@
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
+
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -113,18 +114,49 @@ 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_,
- "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"
- "::google::protobuf::internal::MapField$lite$<\n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ > $name$_;\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");
}
void MapFieldGenerator::
@@ -172,17 +204,6 @@ GenerateSwappingCode(io::Printer* printer) const {
}
void MapFieldGenerator::
-GenerateConstructorCode(io::Printer* printer) const {
- if (HasDescriptorMethods(descriptor_->file(), options_)) {
- printer->Print(variables_,
- "$name$_.SetAssignDescriptorCallback(\n"
- " $file_namespace$::protobuf_AssignDescriptorsOnce);\n"
- "$name$_.SetEntryDescriptor(\n"
- " &$type$_descriptor);\n");
- }
-}
-
-void MapFieldGenerator::
GenerateCopyConstructorCode(io::Printer* printer) const {
GenerateConstructorCode(printer);
GenerateMergingCode(printer);
@@ -199,13 +220,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
string value;
if (IsProto3Field(descriptor_) ||
value_field->type() != FieldDescriptor::TYPE_ENUM) {
- printer->Print(variables_,
+ printer->Print(
+ variables_,
"$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ >,\n"
- " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
+ " $map_classname$,\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ >,\n"
+ " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
" parser(&$name$_);\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
" input, &parser));\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index 816687b3..02e66497 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -54,7 +54,7 @@ class MapFieldGenerator : public FieldGenerator {
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
+ void GenerateConstructorCode(io::Printer* printer) const {}
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 1373ffc2..d9524f64 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -32,6 +32,8 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/cpp/cpp_message.h>
+
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <map>
@@ -41,16 +43,18 @@
#endif
#include <utility>
#include <vector>
-#include <google/protobuf/compiler/cpp/cpp_message.h>
-#include <google/protobuf/compiler/cpp/cpp_field.h>
+
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#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/stubs/strutil.h>
-#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
namespace google {
@@ -103,54 +107,6 @@ struct ExtensionRangeSorter {
}
};
-// Returns true if the "required" restriction check should be ignored for the
-// given field.
-inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
- const Options& options) {
- return false;
-}
-
-// Returns true if the message type has any required fields. If it doesn't,
-// we can optimize out calls to its IsInitialized() method.
-//
-// already_seen is used to avoid checking the same type multiple times
-// (and also to protect against recursion).
-static bool HasRequiredFields(const Descriptor* type, const Options& options,
- hash_set<const Descriptor*>* already_seen) {
- if (already_seen->count(type) > 0) {
- // Since the first occurrence of a required field causes the whole
- // function to return true, we can assume that if the type is already
- // in the cache it didn't have any required fields.
- return false;
- }
- already_seen->insert(type);
-
- // If the type has extensions, an extension with message type could contain
- // required fields, so we have to be conservative and assume such an
- // extension exists.
- if (type->extension_range_count() > 0) return true;
-
- for (int i = 0; i < type->field_count(); i++) {
- const FieldDescriptor* field = type->field(i);
- if (field->is_required()) {
- return true;
- }
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- !ShouldIgnoreRequiredFieldCheck(field, options)) {
- if (HasRequiredFields(field->message_type(), options, already_seen)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool HasRequiredFields(const Descriptor* type, const Options& options) {
- hash_set<const Descriptor*> already_seen;
- return HasRequiredFields(type, options, &already_seen);
-}
-
// 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
@@ -288,10 +244,13 @@ bool CanConstructByZeroing(const FieldDescriptor* field,
// 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
-// declaration order (from the .proto file) so that we don't reduce cache
-// locality much for function that access each field in order. This is also the
-// only (weak) signal we have for author intent concerning field layout.
+// 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.
@@ -346,10 +305,11 @@ void OptimizePadding(std::vector<const FieldDescriptor*>* fields,
f = ZERO_INITIALIZABLE;
}
+ const int j = field->number();
switch (EstimateAlignmentSize(field)) {
- case 1: aligned_to_1[f].push_back(FieldGroup(i, field)); break;
- case 4: aligned_to_4[f].push_back(FieldGroup(i, field)); break;
- case 8: aligned_to_8[f].push_back(FieldGroup(i, field)); break;
+ 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.";
}
@@ -366,7 +326,7 @@ void OptimizePadding(std::vector<const FieldDescriptor*>* fields,
}
aligned_to_4[f].push_back(field_group);
}
- // Sort by preferred location to keep fields as close to their declaration
+ // 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());
@@ -406,9 +366,6 @@ void OptimizePadding(std::vector<const FieldDescriptor*>* fields,
}
}
-string MessageTypeProtoName(const FieldDescriptor* field) {
- return field->message_type()->full_name();
-}
// 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
@@ -495,30 +452,99 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) {
}
+bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) {
+ if (!options.table_driven_parsing) {
+ return false;
+ }
+
+ // Consider table-driven parsing. We only do this if:
+ // - There are no extensions
+ if (descriptor->extension_range_count() != 0) {
+ return false;
+ }
+
+ // - We are not using UnknownFieldSet (part of the non-lite library).
+ if (UseUnknownFieldSet(descriptor->file(), options)) {
+ return false;
+ }
+
+ // - We have has_bits for fields. This avoids a check on every field we set
+ // when are present (the common case).
+ if (!HasFieldPresence(descriptor->file())) {
+ return false;
+ }
+
+ const double table_sparseness = 0.5;
+ int max_field_number = 0;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (max_field_number < field->number()) {
+ max_field_number = field->number();
+ }
+
+ // - There are no map fields.
+ if (field->is_map()) {
+ return false;
+ }
+
+ // - There are no oneof fields.
+ if (field->containing_oneof()) {
+ return false;
+ }
+
+ // - There are no weak fields.
+ if (field->options().weak()) {
+ return false;
+ }
+ }
+
+ // - There range of field numbers is "small"
+ if (max_field_number >= (2 << 14)) {
+ return false;
+ }
+
+ // - Field numbers are relatively dense within the actual number of fields
+ if (max_field_number * table_sparseness >= descriptor->field_count()) {
+ return false;
+ }
+
+ // - This is not a MapEntryMessage.
+ if (IsMapEntryMessage(descriptor)) {
+ return false;
+ }
+
+ return true;
+}
+
} // anonymous namespace
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
- const Options& options)
+ const Options& options,
+ SCCAnalyzer* scc_analyzer)
: descriptor_(descriptor),
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()]),
+ 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) {
-
+ ExtensionGenerator>[descriptor->extension_count()]),
+ use_dependent_base_(false),
+ num_weak_fields_(0),
+ scc_analyzer_(scc_analyzer) {
// Compute optimized field order to be used for layout and initialization
// purposes.
for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->containing_oneof()) {
- optimized_order_.push_back(descriptor_->field(i));
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->options().weak()) {
+ num_weak_fields_++;
+ } else if (!field->containing_oneof()) {
+ optimized_order_.push_back(field);
}
}
OptimizePadding(&optimized_order_, options_);
@@ -538,8 +564,8 @@ 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));
+ nested_generators_[i].reset(new MessageGenerator(descriptor->nested_type(i),
+ options, scc_analyzer));
}
for (int i = 0; i < descriptor->enum_type_count(); i++) {
@@ -565,6 +591,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
// Always make oneofs dependent.
use_dependent_base_ = true;
}
+
+ table_driven_ = TableDrivenEnabled(descriptor_, options_);
}
MessageGenerator::~MessageGenerator() {}
@@ -586,6 +614,7 @@ 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);
}
@@ -602,7 +631,6 @@ void MessageGenerator::AddGenerators(
void MessageGenerator::FillMessageForwardDeclarations(
std::map<string, const Descriptor*>* class_names) {
- if (IsMapEntryMessage(descriptor_)) return;
(*class_names)[classname_] = descriptor_;
}
@@ -644,7 +672,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
ordered_fields.begin(), optimized_order_.begin(), optimized_order_.end());
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (field->containing_oneof() == NULL) {
+ if (field->containing_oneof() == NULL && !field->options().weak()) {
continue;
}
ordered_fields.push_back(field);
@@ -777,6 +805,15 @@ void MessageGenerator::
GenerateSingularFieldHasBits(const FieldDescriptor* field,
std::map<string, string> vars,
io::Printer* printer) {
+ if (field->options().weak()) {
+ printer->Print(
+ vars,
+ "$inline$"
+ "bool $classname$::has_$name$() const {\n"
+ " return _weak_field_map_.Has($number$);\n"
+ "}\n");
+ return;
+ }
if (HasFieldPresence(descriptor_->file())) {
// N.B.: without field presence, we do not use has-bits or generate
// has_$name$() methods.
@@ -896,7 +933,7 @@ GenerateFieldClear(const FieldDescriptor* field,
field_generators_.get(field)
.GenerateClearingCode(printer);
if (HasFieldPresence(descriptor_->file())) {
- if (!field->is_repeated()) {
+ if (!field->is_repeated() && !field->options().weak()) {
printer->Print(vars,
"$this_message$clear_has_$name$();\n");
}
@@ -1049,6 +1086,29 @@ GenerateClassDefinition(io::Printer* printer) {
"}\n"
"\n");
+ // Generate move constructor and move assignment operator for types other than
+ // Any.
+ #ifdef PROTO_EXPERIMENTAL_ENABLE_MOVE
+ if (!IsAnyMessage(descriptor_)) {
+ printer->Print(vars,
+ "#if LANG_CXX11\n"
+ "$classname$($classname$&& from)\n"
+ " : $classname$() {\n"
+ " *this = ::std::move(from);\n"
+ "}\n"
+ "\n"
+ "inline $classname$& operator=($classname$&& from) {\n"
+ " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n"
+ " InternalSwap(&from);\n"
+ " } else {\n"
+ " CopyFrom(from);\n"
+ " }\n"
+ " return *this;\n"
+ "}\n"
+ "#endif\n");
+ }
+ #endif
+
if (PreserveUnknownFields(descriptor_)) {
string type = UseUnknownFieldSet(descriptor_->file(), options_)
? "::google::protobuf::UnknownFieldSet"
@@ -1119,12 +1179,15 @@ GenerateClassDefinition(io::Printer* printer) {
}
// TODO(gerbens) make this private, while still granting other protos access.
+ vars["message_index"] = SimpleItoa(index_in_file_messages_);
printer->Print(
vars,
"static inline const $classname$* internal_default_instance() {\n"
" return reinterpret_cast<const $classname$*>(\n"
" &_$classname$_default_instance_);\n"
"}\n"
+ "static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =\n"
+ " $message_index$;\n"
"\n");
@@ -1199,14 +1262,8 @@ GenerateClassDefinition(io::Printer* printer) {
}
if (HasFastArraySerialization(descriptor_->file(), options_)) {
printer->Print(
- "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
- " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n"
- "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)\n"
- " const PROTOBUF_FINAL {\n"
- " return InternalSerializeWithCachedSizesToArray(\n"
- " ::google::protobuf::io::CodedOutputStream::"
- "IsDefaultSerializationDeterministic(), output);\n"
- "}\n");
+ "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
+ " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n");
}
}
@@ -1312,7 +1369,8 @@ GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
- if (!descriptor_->field(i)->is_repeated()) {
+ if (!descriptor_->field(i)->is_repeated() &&
+ !descriptor_->field(i)->options().weak()) {
// set_has_***() generated in all proto1/2 code and in oneofs (only) for
// messages without true field presence.
if (HasFieldPresence(descriptor_->file()) ||
@@ -1451,6 +1509,10 @@ GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+ if (num_weak_fields_) {
+ printer->Print(
+ "::google::protobuf::internal::WeakFieldMap _weak_field_map_;\n");
+ }
// Generate _any_metadata_ for the Any type.
if (IsAnyMessage(descriptor_)) {
printer->Print(vars,
@@ -1459,6 +1521,7 @@ 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.
printer->Print(
@@ -1511,8 +1574,9 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) {
void MessageGenerator::
GenerateExtraDefaultFields(io::Printer* printer) {
- // Generate oneof default instance for reflection usage.
- if (descriptor_->oneof_decl_count() > 0) {
+ // Generate oneof default instance and weak field instances for reflection
+ // usage.
+ if (descriptor_->oneof_decl_count() > 0 || num_weak_fields_ > 0) {
printer->Print("public:\n");
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
@@ -1525,9 +1589,71 @@ GenerateExtraDefaultFields(io::Printer* printer) {
field_generators_.get(field).GeneratePrivateMembers(printer);
}
}
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->options().weak()) {
+ printer->Print(
+ " const ::google::protobuf::Message* $name$_;\n", "name", FieldName(field));
+ }
+ }
}
}
+bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
+ size_t aux_offset) {
+ if (!table_driven_) {
+ printer->Print("{ NULL, NULL, 0, -1, -1, false },\n");
+ return false;
+ }
+
+ std::map<string, string> vars;
+
+ vars["classname"] = classname_;
+ vars["offset"] = SimpleItoa(offset);
+ vars["aux_offset"] = SimpleItoa(aux_offset);
+
+ int max_field_number = 0;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (max_field_number < field->number()) {
+ max_field_number = field->number();
+ }
+ }
+
+ vars["max_field_number"] = SimpleItoa(max_field_number);
+
+ printer->Print("{\n");
+ printer->Indent();
+
+ printer->Print(vars,
+ "TableStruct::entries + $offset$,\n"
+ "TableStruct::aux + $aux_offset$,\n"
+ "$max_field_number$,\n");
+
+ if (!HasFieldPresence(descriptor_->file())) {
+ // If we don't have field presence, then _has_bits_ does not exist.
+ printer->Print(vars, "-1,\n");
+ } else {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classname$, _has_bits_),\n");
+ }
+
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classname$, _internal_metadata_),\n");
+
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars, "true,\n");
+ } else {
+ printer->Print(vars, "false,\n");
+ }
+
+ printer->Outdent();
+ printer->Print("},\n");
+ return true;
+}
+
void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
int has_offset) {
if (IsMapEntryMessage(descriptor_)) return;
@@ -1545,46 +1671,7 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
}
void MessageGenerator::
-GenerateTypeRegistrations(io::Printer* printer) {
- // Register this message type with the message factory.
- if (IsMapEntryMessage(descriptor_)) {
- std::map<string, string> vars;
- CollectMapInfo(descriptor_, &vars);
- vars["classname"] = classname_;
- vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name());
-
- const FieldDescriptor* val = descriptor_->FindFieldByName("value");
- if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
- 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";
- }
-
- vars["index_in_metadata"] = SimpleItoa(index_in_metadata_);
-
- printer->Print(
- vars,
- "const ::google::protobuf::Descriptor* $classname$_descriptor = "
- "$file_namespace$::file_level_metadata[$index_in_metadata$].descriptor;"
- "\n"
- "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
- " $classname$_descriptor,\n"
- " ::google::protobuf::internal::MapEntry<\n"
- " $key$,\n"
- " $val$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$>::CreateDefaultInstance(\n"
- " $classname$_descriptor));\n");
- }
-}
-
-void MessageGenerator::
GenerateDefaultInstanceAllocator(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
-
// Construct the default instances of all fields, as they will be used
// when creating the default instance of the entire message.
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1601,7 +1688,15 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) {
void MessageGenerator::
GenerateDefaultInstanceInitializer(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
+ if (IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "_$classname$_default_instance_.get_mutable()->set_default_instance(_$"
+ "classname$_default_instance_.get_mutable());\n"
+ "_$classname$_default_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
@@ -1617,7 +1712,7 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
(field->containing_oneof() == NULL ||
HasDescriptorMethods(descriptor_->file(), options_))) {
string name;
- if (field->containing_oneof()) {
+ if (field->containing_oneof() || field->options().weak()) {
name = "_" + classname_ + "_default_instance_.";
} else {
name = "_" + classname_ + "_default_instance_.get_mutable()->";
@@ -1645,7 +1740,7 @@ GenerateShutdownCode(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print("delete file_level_metadata[$index$].reflection;\n", "index",
- SimpleItoa(index_in_metadata_));
+ SimpleItoa(index_in_file_messages_));
}
// Handle default instances of fields.
@@ -1657,7 +1752,31 @@ GenerateShutdownCode(io::Printer* printer) {
void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
+ if (IsMapEntryMessage(descriptor_)) {
+ 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"
+ "}\n"
+ "void $parent$::$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),
+ "classname", classname_, "index",
+ SimpleItoa(index_in_file_messages_));
+ }
+ return;
+ }
if (IsAnyMessage(descriptor_)) {
printer->Print(
@@ -1739,11 +1858,12 @@ GenerateClassMethods(io::Printer* printer) {
printer->Print(
"::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return $file_namespace$::file_level_metadata[$index$];\n"
+ " return "
+ "$file_namespace$::file_level_metadata[kIndexInFileMessages];\n"
"}\n"
"\n",
- "classname", classname_, "index", SimpleItoa(index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_->file()->name()));
} else {
printer->Print(
"::std::string $classname$::GetTypeName() const {\n"
@@ -1756,6 +1876,185 @@ GenerateClassMethods(io::Printer* printer) {
}
+size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
+ if (!table_driven_) {
+ return 0;
+ }
+
+ // Field "0" is special: We use it in our switch statement of processing
+ // types to handle the successful end tag case.
+ printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n");
+ int last_field_number = 1;
+
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+ GOOGLE_CHECK_GE(field->number(), last_field_number);
+
+ for (; last_field_number < field->number(); last_field_number++) {
+ printer->Print(
+ "{ 0, 0, ::google::protobuf::internal::kInvalidMask,\n"
+ " ::google::protobuf::internal::kInvalidMask, 0, 0 },\n");
+ }
+ last_field_number++;
+
+ unsigned char normal_wiretype, packed_wiretype, processing_type;
+ normal_wiretype = WireFormat::WireTypeForFieldType(field->type());
+
+ if (field->is_packable()) {
+ packed_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+ } else {
+ packed_wiretype = internal::kNotPackedMask;
+ }
+
+ processing_type = static_cast<unsigned>(field->type());
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ default:
+ break;
+ }
+ } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ default:
+ break;
+ }
+ }
+
+ processing_type |= static_cast<unsigned>(
+ field->is_repeated() ? internal::kRepeatedMask : 0);
+ const unsigned char tag_size =
+ WireFormat::TagSize(field->number(), field->type());
+
+ std::map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["name"] = FieldName(field);
+ vars["has"] = SimpleItoa(has_bit_indices_[field->index()]);
+ vars["nwtype"] = SimpleItoa(normal_wiretype);
+ vars["pwtype"] = SimpleItoa(packed_wiretype);
+ vars["ptype"] = SimpleItoa(processing_type);
+ vars["tag_size"] = SimpleItoa(tag_size);
+
+ printer->Print(vars,
+ "{\n"
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classname$, $name$_),\n"
+ " static_cast< ::google::protobuf::uint32>($has$),\n"
+ " $nwtype$, $pwtype$, $ptype$, $tag_size$\n"
+ "},\n");
+ }
+
+ return last_field_number;
+}
+
+size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
+ if (!table_driven_) {
+ return 0;
+ }
+
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
+
+ printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ int last_field_number = 1;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = ordered_fields[i];
+
+ GOOGLE_CHECK_GE(field->number(), last_field_number);
+ for (; last_field_number < field->number(); last_field_number++) {
+ printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n");
+ }
+
+ std::map<string, string> vars;
+ SetCommonFieldVariables(field, &vars, options_);
+
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_ENUM:
+ vars["type"] = ClassName(field->enum_type(), true);
+ printer->Print(
+ vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::enum_aux{"
+ "$type$_IsValid, \"$type$\" }},\n");
+ 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();
+
+ vars["classname"] = ClassName(field->message_type(), false);
+ vars["ns"] = Join(package_parts, "::");
+ vars["type"] = FieldMessageTypeName(field);
+ vars["file_namespace"] = FileLevelNamespace(outer->file()->name());
+
+ printer->Print(vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n"
+ " &::$ns$_$classname$_default_instance_,\n");
+
+ bool dont_emit_table =
+ !TableDrivenEnabled(field->message_type(), options_);
+
+ if (dont_emit_table) {
+ printer->Print(" NULL,\n");
+ } else {
+ printer->Print(vars,
+ " ::$ns$$file_namespace$::TableStruct::schema +\n"
+ " ::$ns$$classname$::kIndexInFileMessages,\n");
+ }
+
+ printer->Print("}},\n");
+ last_field_number++;
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING:
+ switch (EffectiveStringCType(field)) {
+ case FieldOptions::STRING:
+ vars["default"] =
+ field->default_value_string().empty()
+ ? "&::google::protobuf::internal::fixed_address_empty_string"
+ : "&" + classname_ + "::_default_" + FieldName(field) + "_";
+ break;
+ case FieldOptions::CORD:
+ case FieldOptions::STRING_PIECE:
+ vars["default"] =
+ "\"" + CEscape(field->default_value_string()) + "\"";
+ break;
+ }
+ vars["full_name"] = field->full_name();
+ vars["strict"] =
+ field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3
+ ? "true" : "false";
+ vars["type"] = field->full_name();
+ printer->Print(vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::string_aux{\n"
+ " $default$,\n"
+ " \"$full_name$\",\n"
+ " $strict$,\n"
+ " \"$type$\"\n"
+ "}},\n");
+ last_field_number++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return last_field_number;
+}
+
std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
io::Printer* printer) {
if (IsMapEntryMessage(descriptor_)) return std::make_pair(0, 0);
@@ -1765,7 +2064,8 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
if (HasFieldPresence(descriptor_->file())) {
printer->Print(
variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_has_bits_),\n");
} else {
printer->Print("~0u, // no _has_bits_\n");
}
@@ -1775,34 +2075,41 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
if (descriptor_->extension_range_count() > 0) {
printer->Print(
variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _extensions_),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_extensions_),\n");
} else {
printer->Print("~0u, // no _extensions_\n");
}
if (descriptor_->oneof_decl_count() > 0) {
printer->Print(variables,
- "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "_oneof_case_[0]),\n");
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _oneof_case_[0]),\n");
} else {
printer->Print("~0u, // no _oneof_case_\n");
}
-
- const int kNumGenericOffsets = 4; // the number of fixed offsets above
+ if (num_weak_fields_ > 0) {
+ printer->Print(variables,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$,"
+ " _weak_field_map_),\n");
+ } else {
+ printer->Print("~0u, // no _weak_field_map_\n");
+ }
+ const int kNumGenericOffsets = 5; // the number of fixed offsets above
const size_t offsets = kNumGenericOffsets +
descriptor_->field_count() +
descriptor_->oneof_decl_count();
size_t entries = offsets;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
- if (field->containing_oneof()) {
+ if (field->containing_oneof() || field->options().weak()) {
printer->Print(
- "PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET("
+ "GOOGLE_PROTOBUF_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET("
"(&_$classname$_default_instance_), $name$_),\n",
"classname", classname_, "name", FieldName(field));
} else {
printer->Print(
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
- "$name$_),\n",
+ "$name$_),\n",
"classname", classname_,
"name", FieldName(field));
}
@@ -1844,19 +2151,6 @@ GenerateSharedConstructorCode(io::Printer* printer) {
need_to_clear_cached_size = false;
}
- // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer??
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- if (HasDescriptorMethods(descriptor_->file(), options_) &&
- IsMapEntryMessage(descriptor_->nested_type(i))) {
- printer->Print(
- "const ::google::protobuf::Descriptor*& $type$_descriptor = "
- "$file_namespace$::file_level_metadata[$index$].descriptor;\n",
- "type", ClassName(descriptor_->nested_type(i), false), "index",
- SimpleItoa(nested_generators_[i]->index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
- }
- }
-
std::vector<bool> processed(optimized_order_.size(), false);
GenerateConstructorBody(printer, processed, false);
@@ -1906,6 +2200,9 @@ GenerateSharedDestructorCode(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.ClearAll();\n");
+ }
printer->Outdent();
printer->Print(
"}\n"
@@ -1956,6 +2253,12 @@ GenerateArenaDestructorCode(io::Printer* printer) {
}
}
}
+ if (num_weak_fields_) {
+ // _this is the object being destructed (we are inside a static method
+ // here).
+ printer->Print("_this->_weak_field_map_.ClearAll();\n");
+ need_registration = true;
+ }
printer->Outdent();
printer->Print(
@@ -2077,12 +2380,18 @@ GenerateStructors(io::Printer* printer) {
if (IsAnyMessage(descriptor_)) {
initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)";
}
+ if (num_weak_fields_ > 0) {
+ initializer_with_arena += ", _weak_field_map_(arena)";
+ }
string initializer_null;
initializer_null = ", _internal_metadata_(NULL)";
if (IsAnyMessage(descriptor_)) {
initializer_null += ", _any_metadata_(&type_url_, &value_)";
}
+ if (num_weak_fields_ > 0) {
+ initializer_null += ", _weak_field_map_(NULL)";
+ }
printer->Print(
"$classname$::$classname$()\n"
@@ -2165,6 +2474,9 @@ GenerateStructors(io::Printer* printer) {
if (IsAnyMessage(descriptor_)) {
printer->Print(",\n_any_metadata_(&type_url_, &value_)");
}
+ if (num_weak_fields_ > 0) {
+ printer->Print(",\n_weak_field_map_(from._weak_field_map_)");
+ }
printer->Outdent();
printer->Outdent();
@@ -2177,19 +2489,6 @@ GenerateStructors(io::Printer* printer) {
printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
}
- // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer??
- for (int i = 0; i < descriptor_->nested_type_count(); i++) {
- if (HasDescriptorMethods(descriptor_->file(), options_) &&
- IsMapEntryMessage(descriptor_->nested_type(i))) {
- printer->Print(
- "const ::google::protobuf::Descriptor*& $type$_descriptor = "
- "$file_namespace$::file_level_metadata[$index$].descriptor;\n",
- "type", ClassName(descriptor_->nested_type(i), false), "index",
- SimpleItoa(nested_generators_[i]->index_in_metadata_),
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
- }
- }
-
GenerateConstructorBody(printer, processed, true);
// Copy oneof fields. Oneof field requires oneof case check.
@@ -2268,11 +2567,13 @@ GenerateStructors(io::Printer* printer) {
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
" $file_namespace$::protobuf_AssignDescriptorsOnce();\n"
- " return $file_namespace$::file_level_metadata[$index$].descriptor;\n"
+ " return "
+ "$file_namespace$::file_level_metadata[kIndexInFileMessages]."
+ "descriptor;\n"
"}\n"
"\n",
- "index", SimpleItoa(index_in_metadata_), "classname", classname_,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "file_namespace",
+ FileLevelNamespace(descriptor_->file()->name()));
}
printer->Print(
@@ -2504,6 +2805,10 @@ GenerateClear(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.ClearAll();\n");
+ }
+
if (HasFieldPresence(descriptor_->file())) {
// Step 5: Everything else.
printer->Print("_has_bits_.Clear();\n");
@@ -2647,6 +2952,10 @@ GenerateSwap(io::Printer* printer) {
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Swap(&other->_extensions_);\n");
}
+ if (num_weak_fields_) {
+ printer->Print(
+ "_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n");
+ }
} else {
printer->Print("GetReflection()->Swap(this, other);");
}
@@ -2714,7 +3023,14 @@ GenerateMergeFrom(io::Printer* printer) {
}
printer->Print(
- "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
+ "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "(void) cached_has_bits;\n\n");
+
+ // cached_has_bit_index maintains that:
+ // cached_has_bits = from._has_bits_[cached_has_bit_index]
+ // for cached_has_bit_index >= 0
+ int cached_has_bit_index = -1;
int last_i = -1;
for (int i = 0; i < optimized_order_.size(); ) {
@@ -2734,7 +3050,7 @@ GenerateMergeFrom(io::Printer* printer) {
generator.GenerateMergingCode(printer);
}
- // Merge Optional and Required fields (after a _has_bit check).
+ // Merge Optional and Required fields (after a _has_bit_ check).
int last_chunk = -1;
int last_chunk_start = -1;
int last_chunk_end = -1;
@@ -2779,23 +3095,43 @@ GenerateMergeFrom(io::Printer* printer) {
GOOGLE_DCHECK_LE(2, count);
GOOGLE_DCHECK_GE(8, count);
+ if (cached_has_bit_index != last_chunk / 4) {
+ int new_index = last_chunk / 4;
+ printer->Print("cached_has_bits = from._has_bits_[$new_index$];\n",
+ "new_index", SimpleItoa(new_index));
+ cached_has_bit_index = new_index;
+ }
+
printer->Print(
- "if (from._has_bits_[$index$ / 32] & $mask$u) {\n",
- "index", SimpleItoa(last_chunk * 8),
+ "if (cached_has_bits & $mask$u) {\n",
"mask", SimpleItoa(last_chunk_mask));
printer->Indent();
}
// Go back and emit clears for each of the fields we processed.
+ bool deferred_has_bit_changes = false;
for (int j = last_chunk_start; j <= last_chunk_end; j++) {
const FieldDescriptor* field = optimized_order_[j];
const FieldGenerator& generator = field_generators_.get(field);
bool have_enclosing_if = false;
if (HasFieldPresence(descriptor_->file())) {
- printer->Print(
- "if (from.has_$name$()) {\n",
- "name", FieldName(field));
+ // Attempt to use the state of cached_has_bits, if possible.
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (!field->options().weak() &&
+ cached_has_bit_index == has_bit_index / 32) {
+ const string mask = StrCat(
+ strings::Hex(1u << (has_bit_index % 32),
+ strings::ZERO_PAD_8));
+
+ printer->Print(
+ "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask);
+ } else {
+ printer->Print(
+ "if (from.has_$name$()) {\n",
+ "name", FieldName(field));
+ }
+
printer->Indent();
have_enclosing_if = true;
} else {
@@ -2805,7 +3141,17 @@ GenerateMergeFrom(io::Printer* printer) {
printer, "from.", field);
}
- generator.GenerateMergingCode(printer);
+ if (have_outer_if && IsPOD(field)) {
+ // GenerateCopyConstructorCode for enum and primitive scalar fields
+ // does not do _has_bits_ modifications. We defer _has_bits_
+ // manipulation until the end of the outer if.
+ //
+ // This can reduce the number of loads/stores by up to 7 per 8 fields.
+ deferred_has_bit_changes = true;
+ generator.GenerateCopyConstructorCode(printer);
+ } else {
+ generator.GenerateMergingCode(printer);
+ }
if (have_enclosing_if) {
printer->Outdent();
@@ -2814,6 +3160,14 @@ GenerateMergeFrom(io::Printer* printer) {
}
if (have_outer_if) {
+ if (deferred_has_bit_changes) {
+ // Flush the has bits for the primitives we deferred.
+ GOOGLE_CHECK_LE(0, cached_has_bit_index);
+ printer->Print(
+ "_has_bits_[$index$] |= cached_has_bits;\n",
+ "index", SimpleItoa(cached_has_bit_index));
+ }
+
printer->Outdent();
printer->Print("}\n");
}
@@ -2849,6 +3203,9 @@ GenerateMergeFrom(io::Printer* printer) {
printer->Print(
"}\n");
}
+ if (num_weak_fields_) {
+ printer->Print("_weak_field_map_.MergeFrom(from._weak_field_map_);\n");
+ }
printer->Outdent();
printer->Print("}\n");
@@ -2913,13 +3270,36 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
return;
}
+ std::vector<const FieldDescriptor*> ordered_fields =
+ SortFieldsByNumber(descriptor_);
+
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input) {\n"
- "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
- " ::google::protobuf::uint32 tag;\n",
+ " ::google::protobuf::io::CodedInputStream* input) {\n",
"classname", classname_);
+ if (table_driven_) {
+ printer->Indent();
+
+ printer->Print(
+ "return ::google::protobuf::internal::MergePartialFromCodedStream(\n"
+ " this,\n"
+ " $file_namespace$::TableStruct::schema[\n"
+ " $classname$::kIndexInFileMessages],\n"
+ " input);\n",
+ "classname", classname_,
+ "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+
+ printer->Outdent();
+
+ printer->Print("}\n");
+ return;
+ }
+
+ printer->Print(
+ "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
+ " ::google::protobuf::uint32 tag;\n");
+
if (PreserveUnknownFields(descriptor_) &&
!UseUnknownFieldSet(descriptor_->file(), options_)) {
// Use LazyStringOutputString to avoid initializing unknown fields string
@@ -2928,7 +3308,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print(
" ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
" ::google::protobuf::NewPermanentCallback(&_internal_metadata_,\n"
- " &::google::protobuf::internal::InternalMetadataWithArenaLite::mutable_unknown_fields));\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_);
@@ -2942,8 +3323,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("for (;;) {\n");
printer->Indent();
- std::vector<const FieldDescriptor*> ordered_fields =
- SortFieldsByNumber(descriptor_);
uint32 maxtag = descriptor_->field_count() == 0 ? 0 :
WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]);
const int kCutoff0 = 127; // fits in 1-byte varint
@@ -3004,20 +3383,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Indent();
- // Find repeated messages and groups now, to simplify what follows.
- hash_set<int> fields_with_parse_loop;
- for (int i = 0; i < ordered_fields.size(); i++) {
- const FieldDescriptor* field = ordered_fields[i];
- if (field->is_repeated() &&
- (field->type() == FieldDescriptor::TYPE_MESSAGE ||
- field->type() == FieldDescriptor::TYPE_GROUP)) {
- fields_with_parse_loop.insert(i);
- }
- }
-
for (int i = 0; i < ordered_fields.size(); i++) {
const FieldDescriptor* field = ordered_fields[i];
- const bool loops = fields_with_parse_loop.count(i) > 0;
PrintFieldComment(printer, field);
@@ -3030,11 +3397,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// Emit code to parse the common, expected case.
printer->Print("if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
" static_cast< ::google::protobuf::uint8>($commontag$u)) {\n",
- "commontag", SimpleItoa(WireFormat::MakeTag(field)));
-
- if (loops) {
- printer->Print(" DO_(input->IncrementRecursionDepth());\n");
- }
+ "commontag", SimpleItoa(WireFormat::MakeTag(field)));
printer->Indent();
if (field->is_packed()) {
@@ -3074,12 +3437,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
" goto handle_unusual;\n"
"}\n");
- // For repeated messages/groups, we need to decrement recursion depth.
- if (loops) {
- printer->Print(
- "input->UnsafeDecrementRecursionDepth();\n");
- }
-
printer->Print(
"break;\n");
@@ -3194,7 +3551,7 @@ void MessageGenerator::GenerateSerializeOneofFields(
bool to_array) {
GOOGLE_CHECK(!fields.empty());
if (fields.size() == 1) {
- GenerateSerializeOneField(printer, fields[0], to_array);
+ GenerateSerializeOneField(printer, fields[0], to_array, -1);
return;
}
// We have multiple mutually exclusive choices. Emit a switch statement.
@@ -3227,14 +3584,31 @@ void MessageGenerator::GenerateSerializeOneofFields(
}
void MessageGenerator::GenerateSerializeOneField(
- io::Printer* printer, const FieldDescriptor* field, bool to_array) {
- PrintFieldComment(printer, field);
+ io::Printer* printer, const FieldDescriptor* field, bool to_array,
+ int cached_has_bits_index) {
+ if (!field->options().weak()) {
+ // For weakfields, PrintFieldComment is called during iteration.
+ PrintFieldComment(printer, field);
+ }
bool have_enclosing_if = false;
- if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
- printer->Print(
- "if (has_$name$()) {\n",
- "name", FieldName(field));
+ if (field->options().weak()) {
+ } else if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
+ // Attempt to use the state of cached_has_bits, if possible.
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (cached_has_bits_index == has_bit_index / 32) {
+ const string mask = StrCat(
+ strings::Hex(1u << (has_bit_index % 32),
+ strings::ZERO_PAD_8));
+
+ printer->Print(
+ "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask);
+ } else {
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ }
+
printer->Indent();
have_enclosing_if = true;
} else if (!HasFieldPresence(descriptor_->file())) {
@@ -3341,7 +3715,6 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- printer->Print("(void)deterministic; // Unused\n");
printer->Print(
"// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n",
"full_name", descriptor_->full_name());
@@ -3372,7 +3745,8 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
: mg_(mg),
printer_(printer),
to_array_(to_array),
- eager_(!HasFieldPresence(mg->descriptor_->file())) {}
+ eager_(!HasFieldPresence(mg->descriptor_->file())),
+ cached_has_bit_index_(-1) {}
~LazySerializerEmitter() { Flush(); }
@@ -3383,7 +3757,27 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
Flush();
}
if (field->containing_oneof() == NULL) {
- mg_->GenerateSerializeOneField(printer_, field, to_array_);
+ // TODO(ckennelly): Defer non-oneof fields similarly to oneof fields.
+
+ if (!field->options().weak() && !field->is_repeated() && !eager_) {
+ // We speculatively load the entire _has_bits_[index] contents, even
+ // if it is for only one field. Deferring non-oneof emitting would
+ // allow us to determine whether this is going to be useful.
+ int has_bit_index = mg_->has_bit_indices_[field->index()];
+ if (cached_has_bit_index_ != has_bit_index / 32) {
+ // Reload.
+ int new_index = has_bit_index / 32;
+
+ printer_->Print(
+ "cached_has_bits = _has_bits_[$new_index$];\n",
+ "new_index", SimpleItoa(new_index));
+
+ cached_has_bit_index_ = new_index;
+ }
+ }
+
+ mg_->GenerateSerializeOneField(
+ printer_, field, to_array_, cached_has_bit_index_);
} else {
v_.push_back(field);
}
@@ -3409,6 +3803,11 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
const bool to_array_;
const bool eager_;
std::vector<const FieldDescriptor*> v_;
+
+ // cached_has_bit_index_ maintains that:
+ // cached_has_bits = from._has_bits_[cached_has_bit_index_]
+ // for cached_has_bit_index_ >= 0
+ int cached_has_bit_index_;
};
std::vector<const FieldDescriptor*> ordered_fields =
@@ -3420,29 +3819,51 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
std::sort(sorted_extensions.begin(), sorted_extensions.end(),
ExtensionRangeSorter());
+ if (num_weak_fields_) {
+ printer->Print(
+ "::google::protobuf::internal::WeakFieldMap::FieldWriter field_writer("
+ "_weak_field_map_);\n");
+ }
+
+ printer->Print(
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "(void) cached_has_bits;\n\n");
// Merge the fields and the extension ranges, both sorted by field number.
{
LazySerializerEmitter e(this, printer, to_array);
+ const FieldDescriptor* last_weak_field = NULL;
int i, j;
for (i = 0, j = 0;
i < ordered_fields.size() || j < sorted_extensions.size();) {
- if (i == descriptor_->field_count()) {
- e.Flush();
- GenerateSerializeOneExtensionRange(printer,
- sorted_extensions[j++],
- to_array);
- } else if (j == sorted_extensions.size()) {
- e.Emit(ordered_fields[i++]);
- } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) {
- e.Emit(ordered_fields[i++]);
- } else {
+ if ((j == sorted_extensions.size()) ||
+ (i < descriptor_->field_count() &&
+ ordered_fields[i]->number() < sorted_extensions[j]->start)) {
+ const FieldDescriptor* field = ordered_fields[i++];
+ if (field->options().weak()) {
+ last_weak_field = field;
+ PrintFieldComment(printer, field);
+ } else {
+ if (last_weak_field != NULL) {
+ e.Emit(last_weak_field);
+ last_weak_field = NULL;
+ }
+ e.Emit(field);
+ }
+ } else {
+ if (last_weak_field != NULL) {
+ e.Emit(last_weak_field);
+ last_weak_field = NULL;
+ }
e.Flush();
GenerateSerializeOneExtensionRange(printer,
sorted_extensions[j++],
to_array);
}
}
+ if (last_weak_field != NULL) {
+ e.Emit(last_weak_field);
+ }
}
if (PreserveUnknownFields(descriptor_)) {
@@ -3783,6 +4204,11 @@ GenerateByteSize(io::Printer* printer) {
"}\n");
}
+ if (num_weak_fields_) {
+ // TagSize + MessageSize
+ printer->Print("total_size += _weak_field_map_.ByteSizeLong();\n");
+ }
+
// We update _cached_size_ even though this is a const method. In theory,
// this is not thread-compatible, because concurrent writes have undefined
// results. In practice, since any concurrent writes will be writing the
@@ -3840,26 +4266,28 @@ GenerateIsInitialized(io::Printer* printer) {
// TODO(ckennelly): Push this down into a generator?
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
if (field->is_repeated()) {
printer->Print(
"if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
" return false;\n",
"name", FieldName(field));
+ } else if (field->options().weak()) {
+ continue;
} else {
- GOOGLE_CHECK(field->options().weak() || !field->containing_oneof());
- // For weak fields, use the data member (::google::protobuf::Message*) instead
- // of the getter to avoid a link dependency on the weak message type
- // which is only forward declared.
+ GOOGLE_CHECK(!field->containing_oneof());
printer->Print(
"if (has_$name$()) {\n"
" if (!this->$name$_->IsInitialized()) return false;\n"
"}\n",
- "name", FieldName(field));
+ "name", FieldName(field));
}
}
}
-
+ if (num_weak_fields_) {
+ // For Weak fields.
+ printer->Print("if (!_weak_field_map_.IsInitialized()) return false;\n");
+ }
// Go through the oneof fields, emitting a switch if any might have required
// fields.
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -3871,7 +4299,7 @@ GenerateIsInitialized(io::Printer* printer) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
has_required_fields = true;
break;
}
@@ -3894,17 +4322,10 @@ GenerateIsInitialized(io::Printer* printer) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
- HasRequiredFields(field->message_type(), options_)) {
+ scc_analyzer_->HasRequiredFields(field->message_type())) {
GOOGLE_CHECK(!(field->options().weak() || !field->containing_oneof()));
if (field->options().weak()) {
- // For weak fields, use the data member (::google::protobuf::Message*) instead
- // of the getter to avoid a link dependency on the weak message type
- // which is only forward declared.
- printer->Print(
- "if (has_$name$()) {\n"
- " if (!this->$name$_->IsInitialized()) return false;\n"
- "}\n",
- "name", FieldName(field));
+ // Just skip.
} else {
printer->Print(
"if (has_$name$()) {\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 1a804a16..23aaeeb0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -42,6 +42,7 @@
#include <set>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_options.h>
namespace google {
@@ -61,7 +62,8 @@ class ExtensionGenerator; // extension.h
class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
- MessageGenerator(const Descriptor* descriptor, const Options& options);
+ MessageGenerator(const Descriptor* descriptor, const Options& options,
+ SCCAnalyzer* scc_analyzer);
~MessageGenerator();
// Appends the pre-order walk of the nested generators to list.
@@ -94,10 +96,6 @@ class MessageGenerator {
// Generate extra fields
void GenerateExtraDefaultFields(io::Printer* printer);
- // Generate code that calls MessageFactory::InternalRegisterGeneratedMessage()
- // for all types.
- void GenerateTypeRegistrations(io::Printer* printer);
-
// Generates code that allocates the message's default instance.
void GenerateDefaultInstanceAllocator(io::Printer* printer);
@@ -121,6 +119,15 @@ class MessageGenerator {
void GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
+ // Generate the table-driven parsing array. Returns the number of entries
+ // generated.
+ size_t GenerateParseOffsets(io::Printer* printer);
+ size_t GenerateParseAuxTable(io::Printer* printer);
+ // Generates a ParseTable entry. Returns whether the proto uses table-driven
+ // parsing.
+ bool GenerateParseTable(io::Printer* printer, size_t offset,
+ size_t aux_offset);
+
// Generate the field offsets array. Returns the a pair of the total numer
// of entries generated and the index of the first has_bit entry.
std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
@@ -155,9 +162,14 @@ class MessageGenerator {
void GenerateIsInitialized(io::Printer* printer);
// Helpers for GenerateSerializeWithCachedSizes().
+ //
+ // cached_has_bit_index maintains that:
+ // cached_has_bits = _has_bits_[cached_has_bit_index]
+ // for cached_has_bit_index >= 0
void GenerateSerializeOneField(io::Printer* printer,
const FieldDescriptor* field,
- bool unbounded);
+ bool unbounded,
+ int cached_has_bits_index);
// Generate a switch statement to serialize 2+ fields from the same oneof.
// Or, if fields.size() == 1, just call GenerateSerializeOneField().
void GenerateSerializeOneofFields(
@@ -197,7 +209,7 @@ class MessageGenerator {
// optimized_order_ is the order we layout the message's fields in the class.
// This is reused to initialize the fields in-order for cache efficiency.
//
- // optimized_order_ excludes oneof fields.
+ // optimized_order_ excludes oneof fields and weak fields.
std::vector<const FieldDescriptor *> optimized_order_;
std::vector<int> has_bit_indices_;
int max_has_bit_index_;
@@ -206,8 +218,13 @@ class MessageGenerator {
google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
int num_required_fields_;
bool use_dependent_base_;
+ int num_weak_fields_;
+ // table_driven_ indicates the generated message uses table-driven parsing.
+ bool table_driven_;
+
+ int index_in_file_messages_;
- int index_in_metadata_;
+ SCCAnalyzer* scc_analyzer_;
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 c3d1745c..fc3c4564 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -35,6 +35,7 @@
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
+
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -583,7 +584,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
" InternalWrite$declared_type$NoVirtualToArray(\n"
- " $number$, *$non_null_ptr_to_name$, false, target);\n");
+ " $number$, *$non_null_ptr_to_name$, deterministic, target);\n");
}
void MessageFieldGenerator::
@@ -670,15 +671,6 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
InternalGenerateInlineAccessorDefinitions(variables, printer);
}
-void MessageOneofFieldGenerator::
-GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
- std::map<string, string> variables(variables_);
- variables["field_member"] =
- variables["oneof_prefix"] + variables["name"] + "_";
-
- //printer->Print(variables,
-}
-
void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions(
const std::map<string, string>& variables, io::Printer* printer) const {
printer->Print(variables,
@@ -1066,7 +1058,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedMessageFieldGenerator::
@@ -1079,12 +1071,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::"
- "ReadMessageNoVirtualNoRecursionDepth(\n"
+ "ReadMessageNoVirtual(\n"
" input, add_$name$()));\n");
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::"
- "ReadGroupNoVirtualNoRecursionDepth(\n"
+ "ReadGroupNoVirtual(\n"
" $number$, input, add_$name$()));\n");
}
}
@@ -1104,7 +1096,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
"for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" InternalWrite$declared_type$NoVirtualToArray(\n"
- " $number$, this->$name$(i), false, target);\n"
+ " $number$, this->$name$(i), deterministic, target);\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 9ca91153..cd9737f0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -95,7 +95,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const;
- void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
+ void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { }
void GenerateClearingCode(io::Printer* printer) const;
// MessageFieldGenerator, from which we inherit, overrides this so we need to
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index ee44fb0a..bdaa12a5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -46,16 +46,18 @@ struct Options {
Options()
: safe_boundary_check(false),
proto_h(false),
- allow_import_public(true),
+ transitive_pb_h(true),
annotate_headers(false),
- enforce_lite(false) {}
+ enforce_lite(false),
+ table_driven_parsing(false) {}
string dllexport_decl;
bool safe_boundary_check;
bool proto_h;
- bool allow_import_public;
+ bool transitive_pb_h;
bool annotate_headers;
bool enforce_lite;
+ bool table_driven_parsing;
string annotation_pragma_name;
string annotation_guard_name;
};
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 4a0a23f6..020c1941 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -342,7 +342,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedPrimitiveFieldGenerator::
@@ -385,6 +385,9 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
" output->WriteVarint32(_$name$_cached_byte_size_);\n");
if (FixedSize(descriptor_->type()) > 0) {
+ // TODO(ckennelly): Use RepeatedField<T>::unsafe_data() via
+ // WireFormatLite to access the contents of this->$name$_ to save a branch
+ // here.
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$Array(\n"
" this->$name$().data(), this->$name$_size(), output);\n");
@@ -420,20 +423,14 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
" _$name$_cached_byte_size_, target);\n"
- "}\n");
- }
- printer->Print(variables_,
- "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
- if (descriptor_->is_packed()) {
- printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::\n"
- " Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
+ " Write$declared_type$NoTagToArray(this->$name$_, target);\n"
+ "}\n");
} else {
printer->Print(variables_,
- " target = ::google::protobuf::internal::WireFormatLite::\n"
- " Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
+ "target = ::google::protobuf::internal::WireFormatLite::\n"
+ " Write$declared_type$ToArray($number$, this->$name$_, target);\n");
}
- printer->Print("}\n");
}
void RepeatedPrimitiveFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 664a2779..7a849e2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -36,6 +36,7 @@
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
+
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -61,6 +62,7 @@ void SetStringVariables(const FieldDescriptor* descriptor,
".get()";
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
+ (*variables)["null_check"] = "GOOGLE_DCHECK(value != NULL);\n";
// NOTE: Escaped here to unblock proto1->proto2 migration.
// TODO(liujisi): Extend this to apply for other conflicting methods.
(*variables)["release_name"] =
@@ -190,6 +192,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
+ " $null_check$"
" $set_hasbit$\n"
" $name$_.Set($default_variable$, $string_piece$(value),\n"
" GetArenaNoVirtual());\n"
@@ -267,6 +270,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"}\n"
"#endif\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
+ " $null_check$"
" $set_hasbit$\n"
" $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
@@ -548,6 +552,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
+ " $null_check$"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -664,6 +669,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"}\n"
"#endif\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
+ " $null_check$"
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
@@ -882,6 +888,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"}\n"
"#endif\n"
"$inline$void $classname$::set_$name$(int index, const char* value) {\n"
+ " $null_check$"
" $name$_.Mutable(index)->assign(value);\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n"
@@ -902,11 +909,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
"}\n"
"#if LANG_CXX11\n"
"$inline$void $classname$::add_$name$(::std::string&& value) {\n"
- " $name$_.Add()->assign(std::move(value));\n"
+ " $name$_.Add(std::move(value));\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n"
"#endif\n"
"$inline$void $classname$::add_$name$(const char* value) {\n"
+ " $null_check$"
" $name$_.Add()->assign(value);\n"
" // @@protoc_insertion_point(field_add_char:$full_name$)\n"
"}\n"
@@ -939,7 +947,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
}
void RepeatedStringFieldGenerator::
@@ -969,7 +977,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
- "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
+ "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
printer->Indent();
if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 6d68ec35..e56964c7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -76,7 +76,6 @@
#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -2162,6 +2161,61 @@ TEST_F(OneofTest, MergeFrom) {
}
+TEST(HelpersTest, TestSCC) {
+ protobuf_unittest::TestMutualRecursionA a;
+ SCCAnalyzer scc_analyzer((Options()));
+ const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor());
+ std::vector<string> names;
+ for (int i = 0; i < scc->descriptors.size(); i++) {
+ names.push_back(scc->descriptors[i]->full_name());
+ }
+ ASSERT_EQ(names.size(), 4);
+ std::sort(names.begin(), names.end());
+ EXPECT_EQ(names[0], "protobuf_unittest.TestMutualRecursionA");
+ EXPECT_EQ(names[1], "protobuf_unittest.TestMutualRecursionA.SubGroup");
+ EXPECT_EQ(names[2], "protobuf_unittest.TestMutualRecursionA.SubMessage");
+ EXPECT_EQ(names[3], "protobuf_unittest.TestMutualRecursionB");
+
+ MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+ EXPECT_EQ(result.is_recursive, true);
+ EXPECT_EQ(result.contains_required, false);
+ EXPECT_EQ(result.contains_cord, true); // TestAllTypes
+ EXPECT_EQ(result.contains_extension, false); // TestAllTypes
+}
+
+TEST(HelpersTest, TestSCCAnalysis) {
+ {
+ protobuf_unittest::TestRecursiveMessage msg;
+ SCCAnalyzer scc_analyzer((Options()));
+ const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+ MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+ EXPECT_EQ(result.is_recursive, true);
+ EXPECT_EQ(result.contains_required, false);
+ EXPECT_EQ(result.contains_cord, false);
+ EXPECT_EQ(result.contains_extension, false);
+ }
+ {
+ protobuf_unittest::TestAllExtensions msg;
+ SCCAnalyzer scc_analyzer((Options()));
+ const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+ MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+ EXPECT_EQ(result.is_recursive, false);
+ EXPECT_EQ(result.contains_required, false);
+ EXPECT_EQ(result.contains_cord, false);
+ EXPECT_EQ(result.contains_extension, true);
+ }
+ {
+ protobuf_unittest::TestRequired msg;
+ SCCAnalyzer scc_analyzer((Options()));
+ const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor());
+ MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc);
+ EXPECT_EQ(result.is_recursive, false);
+ EXPECT_EQ(result.contains_required, true);
+ EXPECT_EQ(result.contains_cord, false);
+ EXPECT_EQ(result.contains_extension, false);
+ }
+}
+
} // namespace cpp_unittest
} // namespace cpp
} // namespace compiler