aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorGravatar Jisi Liu <jisi.liu@gmail.com>2017-07-18 15:38:30 -0700
committerGravatar Jisi Liu <jisi.liu@gmail.com>2017-07-18 15:38:30 -0700
commit09354db1434859a31a3c81abebcc4018d42f2715 (patch)
treeb87c7cdc2255e6c8062ab92b4082665cd698d753 /src/google/protobuf/compiler/cpp
parent9053033a5076f82cf18b823c31f352e95e5bfd8d (diff)
Merge from Google internal for 3.4 release
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc33
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc32
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h5
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc168
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc31
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h27
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc13
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc811
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h15
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc83
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_move_unittest.cc169
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h4
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc165
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc69
20 files changed, 1210 insertions, 472 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index fce58c02..f99159f5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -125,12 +125,9 @@ 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;
@@ -141,8 +138,6 @@ 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");
@@ -152,10 +147,6 @@ 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.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 6a8a83d1..3b4b97e6 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -81,10 +81,16 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
std::map<string, string> vars;
vars["classname"] = classname_;
vars["short_name"] = descriptor_->name();
- vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
-
- printer->Print(vars, "enum $enumbase$ {\n");
- printer->Annotate("enumbase", descriptor_);
+ vars["enumbase"] = options_.proto_h ? " : int" : "";
+ // These variables are placeholders to pick out the beginning and ends of
+ // identifiers for annotations (when doing so with existing variables would
+ // be ambiguous or impossible). They should never be set to anything but the
+ // empty string.
+ vars["{"] = "";
+ vars["}"] = "";
+
+ printer->Print(vars, "enum $classname$$enumbase$ {\n");
+ printer->Annotate("classname", descriptor_);
printer->Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
@@ -102,7 +108,8 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
" PROTOBUF_DEPRECATED" : "";
if (i > 0) printer->Print(",\n");
- printer->Print(vars, "$prefix$$name$$deprecation$ = $number$");
+ printer->Print(vars, "${$$prefix$$name$$}$$deprecation$ = $number$");
+ printer->Annotate("{", "}", descriptor_->value(i));
if (descriptor_->value(i)->number() < min_value->number()) {
min_value = descriptor_->value(i);
@@ -134,14 +141,20 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
}
printer->Print(vars,
- "$dllexport$bool $classname$_IsValid(int value);\n"
- "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
- "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n");
+ "$dllexport$bool $classname$_IsValid(int value);\n"
+ "const $classname$ ${$$prefix$$short_name$_MIN$}$ = "
+ "$prefix$$min_name$;\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(vars,
+ "const $classname$ ${$$prefix$$short_name$_MAX$}$ = "
+ "$prefix$$max_name$;\n");
+ printer->Annotate("{", "}", descriptor_);
if (generate_array_size_) {
printer->Print(vars,
- "const int $prefix$$short_name$_ARRAYSIZE = "
- "$prefix$$short_name$_MAX + 1;\n\n");
+ "const int ${$$prefix$$short_name$_ARRAYSIZE$}$ = "
+ "$prefix$$short_name$_MAX + 1;\n\n");
+ printer->Annotate("{", "}", descriptor_);
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index c15be942..e99e7e55 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -74,9 +74,11 @@ GeneratePrivateMembers(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n");
+ printer->Annotate("name", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$$type$ $name$() const;\n"
- "$deprecated_attr$void set_$name$($type$ value);\n");
+ "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
}
void EnumFieldGenerator::
@@ -113,7 +115,7 @@ GenerateMergingCode(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+ printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void EnumFieldGenerator::
@@ -257,12 +259,23 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "$deprecated_attr$$type$ $name$(int index) const;\n"
- "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
- "$deprecated_attr$void add_$name$($type$ value);\n");
+ "$deprecated_attr$$type$ $name$(int index) const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$add_$name$$}$($type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n");
+ printer->Annotate("name", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n"
- "$deprecated_attr$::google::protobuf::RepeatedField<int>* mutable_$name$();\n");
+ "$deprecated_attr$::google::protobuf::RepeatedField<int>* "
+ "${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
}
void RepeatedEnumFieldGenerator::
@@ -292,8 +305,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
printer->Print(variables,
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
- "}\n");
- printer->Print(variables,
+ "}\n"
"$inline$const ::google::protobuf::RepeatedField<int>&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index e4fce461..6b1673b2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -35,9 +35,10 @@
#include <google/protobuf/compiler/cpp/cpp_extension.h>
#include <map>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 4480a9d2..dce9617c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -95,6 +95,13 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
// By default, empty string, so that generic code used for both oneofs and
// singular fields can be written.
(*variables)["oneof_prefix"] = "";
+
+ // These variables are placeholders to pick out the beginning and ends of
+ // identifiers for annotations (when doing so with existing variables would
+ // be ambiguous or impossible). They should never be set to anything but the
+ // empty string.
+ (*variables)["{"] = "";
+ (*variables)["}"] = "";
}
void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
@@ -194,7 +201,6 @@ const FieldGenerator& FieldGeneratorMap::get(
return *field_generators_[field->index()];
}
-
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index 00dc25d4..d9dd3850 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -180,10 +180,6 @@ class FieldGenerator {
virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/)
const {}
- // Generate code that should be run when ShutdownProtobufLibrary() is called,
- // to delete all dynamically-allocated objects.
- virtual void GenerateShutdownCode(io::Printer* /*printer*/) const {}
-
// Generate lines to decode this field, which will be placed inside the
// message's MergeFromCodedStream() method.
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
@@ -233,7 +229,6 @@ class FieldGeneratorMap {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
};
-
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index e0542ae8..c56e26f7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -126,12 +126,20 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
new EnumGenerator(file->enum_type(i), options));
enum_generators_.push_back(enum_generators_owner_[i].get());
}
+ for (int i = 0; i < enum_generators_.size(); i++) {
+ enum_generators_[i]->index_in_metadata_ = i;
+ }
for (int i = 0; i < file->service_count(); i++) {
service_generators_owner_[i].reset(
new ServiceGenerator(file->service(i), options));
service_generators_.push_back(service_generators_owner_[i].get());
}
+ if (HasGenericServices(file_, options_)) {
+ for (int i = 0; i < service_generators_.size(); i++) {
+ service_generators_[i]->index_in_metadata_ = i;
+ }
+ }
for (int i = 0; i < file->extension_count(); i++) {
extension_generators_owner_[i].reset(
@@ -526,11 +534,10 @@ class FileGenerator::ForwardDeclarations {
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// AddDescriptors() is a file-level procedure which adds the encoded
// FileDescriptorProto for this .proto file to the global DescriptorPool for
- // generated files (DescriptorPool::generated_pool()). It either runs at
- // static initialization time (by default) or when default_instance() is
- // called for the first time (in LITE_RUNTIME mode with
- // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER flag enabled). This procedure also
- // constructs default instances and registers extensions.
+ // generated files (DescriptorPool::generated_pool()). It ordinarily runs at
+ // static initialization time, but is not used at all in LITE_RUNTIME mode
+ // except when extensions are used. This procedure also constructs default
+ // instances and registers extensions.
//
// Its sibling, AssignDescriptors(), actually pulls the compiled
// FileDescriptor from the DescriptorPool and uses it to populate all of
@@ -546,7 +553,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// table-driven parsing.
printer->Print("PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n"
- " const TableStruct::entries[] = {\n");
+ " const TableStruct::entries[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
std::vector<size_t> entries;
@@ -567,7 +575,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"};\n"
"\n"
"PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n"
- " const TableStruct::aux[] = {\n");
+ " const TableStruct::aux[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
std::vector<size_t> aux_entries;
@@ -586,7 +595,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Print(
"};\n"
"PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n"
- " TableStruct::schema[] = {\n");
+ " TableStruct::schema[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
size_t offset = 0;
@@ -606,9 +616,47 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"};\n"
"\n");
+ if (!message_generators_.empty() && options_.table_driven_serialization) {
+ printer->Print(
+ "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] "
+ "= {\n");
+ printer->Indent();
+ std::vector<int> field_metadata_offsets;
+ int idx = 0;
+ for (int i = 0; i < message_generators_.size(); i++) {
+ field_metadata_offsets.push_back(idx);
+ idx += message_generators_[i]->GenerateFieldMetadata(printer);
+ }
+ field_metadata_offsets.push_back(idx);
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "const ::google::protobuf::internal::SerializationTable "
+ "TableStruct::serialization_table[] = {\n");
+ printer->Indent();
+ // We rely on the order we layout the tables to match the order we
+ // calculate them with FlattenMessagesInFile, so we check here that
+ // these match exactly.
+ std::vector<const Descriptor*> calculated_order =
+ FlattenMessagesInFile(file_);
+ GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size());
+ for (int i = 0; i < message_generators_.size(); i++) {
+ GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_);
+ printer->Print(
+ "{$num_fields$, TableStruct::field_metadata + $index$},\n",
+ "classname", message_generators_[i]->classname_, "num_fields",
+ SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]),
+ "index", SimpleItoa(field_metadata_offsets[i]));
+ }
+ printer->Outdent();
+ printer->Print(
+ "};\n"
+ "\n");
+ }
if (HasDescriptorMethods(file_, options_)) {
if (!message_generators_.empty()) {
- printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] = {\n");
+ printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
std::vector<std::pair<size_t, size_t> > pairs;
for (int i = 0; i < message_generators_.size(); i++) {
@@ -617,8 +665,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Outdent();
printer->Print(
"};\n"
- "\n"
- "static const ::google::protobuf::internal::MigrationSchema schemas[] = {\n");
+ "static const ::google::protobuf::internal::MigrationSchema schemas[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
{
int offset = 0;
@@ -649,7 +697,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// we still need these symbols to exist
printer->Print(
// MSVC doesn't like empty arrays, so we add a dummy.
- "const ::google::protobuf::uint32 TableStruct::offsets[] = { ~0u };\n"
+ "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n"
"static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n"
"static const ::google::protobuf::Message* const* "
"file_default_instances = NULL;\n");
@@ -739,33 +787,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"} // namespace\n");
}
- // -----------------------------------------------------------------
-
- // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
- printer->Print(
- "\n"
- "void TableStruct::Shutdown() {\n");
- printer->Indent();
-
- for (int i = 0; i < message_generators_.size(); i++) {
- message_generators_[i]->GenerateShutdownCode(printer);
- }
-
- if (HasDescriptorMethods(file_, options_)) {
- for (int i = 0; i < message_generators_.size(); i++) {
- if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) continue;
- printer->Print(
- "delete file_level_metadata[$index$].reflection;\n",
- "index", SimpleItoa(i));
- }
- }
-
- printer->Outdent();
- printer->Print(
- "}\n\n");
-
- // -----------------------------------------------------------------
-
// Now generate the InitDefaultsImpl() function.
printer->Print(
"void TableStruct::InitDefaultsImpl() {\n"
@@ -826,7 +847,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
string file_data;
file_proto.SerializeToString(&file_data);
- printer->Print("static const char descriptor[] = {\n");
+ printer->Print("static const char descriptor[] "
+ "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n");
printer->Indent();
if (file_data.size() > 66535) {
@@ -877,9 +899,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
file_namespace);
}
- printer->Print(
- "::google::protobuf::internal::OnShutdown(&TableStruct::Shutdown);\n");
-
printer->Outdent();
printer->Print(
"}\n"
@@ -889,19 +908,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
" ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n"
"}\n");
- if (!StaticInitializersForced(file_, options_)) {
- printer->Print("#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n");
- }
- printer->Print(
- // With static initializers.
- "// Force AddDescriptors() to be called at static initialization time.\n"
- "struct StaticDescriptorInitializer {\n"
- " StaticDescriptorInitializer() {\n"
- " AddDescriptors();\n"
- " }\n"
- "} static_descriptor_initializer;\n");
- if (!StaticInitializersForced(file_, options_)) {
- printer->Print("#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n");
+ if (StaticInitializersForced(file_, options_)) {
+ printer->Print(
+ "// Force AddDescriptors() to be called at dynamic initialization "
+ "time.\n"
+ "struct StaticDescriptorInitializer {\n"
+ " StaticDescriptorInitializer() {\n"
+ " AddDescriptors();\n"
+ " }\n"
+ "} static_descriptor_initializer;\n");
}
}
@@ -925,19 +940,11 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
ForwardDeclarations decls;
- for (int i = 0; i < file_->dependency_count(); i++) {
- FileGenerator dependency(file_->dependency(i), options_);
- dependency.FillForwardDeclarations(&decls);
- }
FillForwardDeclarations(&decls);
decls.Print(printer, options_);
}
void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) {
- for (int i = 0; i < file_->public_dependency_count(); i++) {
- FileGenerator dependency(file_->public_dependency(i), options_);
- dependency.FillForwardDeclarations(decls);
- }
for (int i = 0; i < package_parts_.size(); i++) {
decls = decls->AddOrGetNamespace(package_parts_[i]);
}
@@ -1033,11 +1040,11 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
"#include <google/protobuf/map.h>"
" // IWYU pragma: export\n");
if (HasDescriptorMethods(file_, options_)) {
- printer->Print(
- "#include <google/protobuf/map_field_inl.h>\n");
+ printer->Print("#include <google/protobuf/map_entry.h>\n");
+ printer->Print("#include <google/protobuf/map_field_inl.h>\n");
} else {
- printer->Print(
- "#include <google/protobuf/map_field_lite.h>\n");
+ printer->Print("#include <google/protobuf/map_entry_lite.h>\n");
+ printer->Print("#include <google/protobuf/map_field_lite.h>\n");
}
}
@@ -1104,7 +1111,7 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
void FileGenerator::GenerateGlobalStateFunctionDeclarations(
io::Printer* printer) {
- // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+ // Forward-declare the AddDescriptors, AssignDescriptors
// functions, so that we can declare them to be friends of each class.
printer->Print(
"\n"
@@ -1115,12 +1122,14 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations(
" static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n"
" static const ::google::protobuf::internal::ParseTable schema[];\n"
" static const ::google::protobuf::uint32 offsets[];\n"
+ " static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n"
+ " static const ::google::protobuf::internal::SerializationTable "
+ "serialization_table[];\n"
// The following function(s) need to be able to access private members of
// the messages defined in the file. So we make them static members.
// This is the internal implementation of InitDefaults. It should only
// be called by InitDefaults which makes sure it will be called only once.
" static void InitDefaultsImpl();\n"
- " static void Shutdown();\n"
"};\n"
"void $dllexport_decl$AddDescriptors();\n"
"void $dllexport_decl$InitDefaults();\n"
@@ -1210,6 +1219,13 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
// dependent.
printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+ // TODO(gerbens) remove pragmas when gcc is no longer used. Current version
+ // of gcc fires a bogus error when compiled with strict-aliasing.
+ printer->Print(
+ "#ifdef __GNUC__\n"
+ " #pragma GCC diagnostic push\n"
+ " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n"
+ "#endif // __GNUC__\n");
// Generate class inline methods.
for (int i = 0; i < message_generators_.size(); i++) {
if (i > 0) {
@@ -1219,6 +1235,10 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
message_generators_[i]->GenerateInlineMethods(printer,
/* is_inline = */ true);
}
+ printer->Print(
+ "#ifdef __GNUC__\n"
+ " #pragma GCC diagnostic pop\n"
+ "#endif // __GNUC__\n");
printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
for (int i = 0; i < message_generators_.size(); i++) {
@@ -1235,13 +1255,8 @@ void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
io::Printer* printer) {
// Emit GetEnumDescriptor specializations into google::protobuf namespace:
if (HasEnumDefinitions(file_)) {
- // The SWIG conditional is to avoid a null-pointer dereference
- // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
- // namespace X { void Y<Z::W>(); }
- // which appears in GetEnumDescriptor() specializations.
printer->Print(
"\n"
- "#ifndef SWIG\n"
"namespace google {\nnamespace protobuf {\n"
"\n");
for (int i = 0; i < enum_generators_.size(); i++) {
@@ -1249,8 +1264,7 @@ void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
}
printer->Print(
"\n"
- "} // namespace protobuf\n} // namespace google\n"
- "#endif // SWIG\n");
+ "} // namespace protobuf\n} // namespace google\n");
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index cee31224..68abd0ef 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -100,6 +100,8 @@ bool CppGenerator::Generate(const FileDescriptor* file,
file_options.enforce_lite = true;
} else if (options[i].first == "table_driven_parsing") {
file_options.table_driven_parsing = true;
+ } else if (options[i].first == "table_driven_serialization") {
+ file_options.table_driven_serialization = true;
} else {
*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 9cddba5c..00959796 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -37,14 +37,16 @@
#include <vector>
#include <google/protobuf/stubs/hash.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
+
+
namespace google {
namespace protobuf {
namespace compiler {
@@ -167,6 +169,11 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
}
}
+string DefaultInstanceName(const Descriptor* descriptor) {
+ string prefix = descriptor->file()->package().empty() ? "" : "::";
+ return prefix + DotsToColons(descriptor->file()->package()) + "::_" +
+ ClassName(descriptor, false) + "_default_instance_";
+}
string DependentBaseClassTemplateName(const Descriptor* descriptor) {
return ClassName(descriptor, false) + "_InternalBase";
@@ -654,6 +661,26 @@ void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
"VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer);
}
+namespace {
+
+void Flatten(const Descriptor* descriptor,
+ std::vector<const Descriptor*>* flatten) {
+ for (int i = 0; i < descriptor->nested_type_count(); i++)
+ Flatten(descriptor->nested_type(i), flatten);
+ flatten->push_back(descriptor);
+}
+
+} // namespace
+
+std::vector<const Descriptor*> FlattenMessagesInFile(
+ const FileDescriptor* file) {
+ std::vector<const Descriptor*> result;
+ for (int i = 0; i < file->message_type_count(); i++) {
+ Flatten(file->message_type(i), &result);
+ }
+ return result;
+}
+
bool HasWeakFields(const Descriptor* descriptor) {
return false;
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index a744a865..6ae68591 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -67,6 +67,9 @@ extern const char kThinSeparator[];
string ClassName(const Descriptor* descriptor, bool qualified);
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
+// Fully qualified name of the default_instance of this message.
+string DefaultInstanceName(const Descriptor* descriptor);
+
// Name of the CRTP class template (for use with proto_h).
// This is a class name, like "ProtoName_InternalBase".
string DependentBaseClassTemplateName(const Descriptor* descriptor);
@@ -159,8 +162,18 @@ string SafeFunctionName(const Descriptor* descriptor,
const FieldDescriptor* field,
const string& prefix);
-// Returns true if unknown fields are preseved after parsing.
-inline bool PreserveUnknownFields(const Descriptor* message) {
+// Returns true if unknown fields are always preserved after parsing.
+inline bool AlwaysPreserveUnknownFields(const FileDescriptor* file) {
+ return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// Returns true if unknown fields are preserved after parsing.
+inline bool AlwaysPreserveUnknownFields(const Descriptor* message) {
+ return AlwaysPreserveUnknownFields(message->file());
+}
+
+// Returns true if generated messages have public unknown fields accessors
+inline bool PublicUnknownFieldsAccessors(const Descriptor* message) {
return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
}
@@ -168,10 +181,8 @@ inline bool PreserveUnknownFields(const Descriptor* message) {
::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
const FileDescriptor* file, const Options& options);
-// If PreserveUnknownFields() is true, determines whether unknown
-// fields will be stored in an UnknownFieldSet or a string.
-// If PreserveUnknownFields() is false, this method will not be
-// used.
+// Determines whether unknown fields will be stored in an UnknownFieldSet or
+// a string.
inline bool UseUnknownFieldSet(const FileDescriptor* file,
const Options& options) {
return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
@@ -277,6 +288,10 @@ inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
: file->options().optimize_for();
}
+// This orders the messages in a .pb.cc as it's outputted by file.cc
+std::vector<const Descriptor*> FlattenMessagesInFile(
+ const FileDescriptor* file);
+
bool HasWeakFields(const Descriptor* desc);
bool HasWeakFields(const FileDescriptor* desc);
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 52a3b8b0..5d461401 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -150,6 +150,7 @@ GeneratePrivateMembers(io::Printer* printer) const {
" $map_classname$;\n");
}
printer->Print(variables_,
+ "private:\n"
"::google::protobuf::internal::MapField$lite$<\n"
" $map_classname$,\n"
" $key_cpp$, $val_cpp$,\n"
@@ -161,11 +162,15 @@ GeneratePrivateMembers(io::Printer* printer) const {
void MapFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
- printer->Print(variables_,
+ printer->Print(
+ variables_,
"$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
- " $name$() const;\n"
- "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
- " mutable_$name$();\n");
+ " $name$() const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ " ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
}
void MapFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index d9524f64..752673d0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -52,6 +52,8 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -280,7 +282,7 @@ void OptimizePadding(std::vector<const FieldDescriptor*>* fields,
enum Family {
REPEATED = 0,
STRING = 1,
- MESSAGE = 2,
+ MESSAGE = 3,
ZERO_INITIALIZABLE = 4,
OTHER = 5,
kMaxFamily
@@ -452,22 +454,13 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) {
}
-bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) {
+bool TableDrivenParsingEnabled(
+ 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())) {
@@ -482,16 +475,6 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) {
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;
@@ -503,8 +486,10 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) {
return false;
}
- // - Field numbers are relatively dense within the actual number of fields
- if (max_field_number * table_sparseness >= descriptor->field_count()) {
+ // - Field numbers are relatively dense within the actual number of fields.
+ // We check for strictly greater than in the case where there are no fields
+ // (only extensions) so max_field_number == descriptor->field_count() == 0.
+ if (max_field_number * table_sparseness > descriptor->field_count()) {
return false;
}
@@ -516,6 +501,31 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) {
return true;
}
+void SetUnknkownFieldsVariable(const Descriptor* descriptor,
+ const Options& options,
+ std::map<string, string>* variables) {
+ if (UseUnknownFieldSet(descriptor->file(), options)) {
+ (*variables)["unknown_fields_type"] = "::google::protobuf::UnknownFieldSet";
+ } else {
+ (*variables)["unknown_fields_type"] = "::std::string";
+ }
+ if (AlwaysPreserveUnknownFields(descriptor)) {
+ (*variables)["have_unknown_fields"] =
+ "_internal_metadata_.have_unknown_fields()";
+ (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields()";
+ } else {
+ (*variables)["have_unknown_fields"] =
+ "(_internal_metadata_.have_unknown_fields() && "
+ " ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())";
+ (*variables)["unknown_fields"] =
+ "(::google::protobuf::internal::GetProto3PreserveUnknownsDefault()"
+ " ? _internal_metadata_.unknown_fields()"
+ " : _internal_metadata_.default_instance())";
+ }
+ (*variables)["mutable_unknown_fields"] =
+ "_internal_metadata_.mutable_unknown_fields()";
+}
+
} // anonymous namespace
// ===================================================================
@@ -592,7 +602,7 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
use_dependent_base_ = true;
}
- table_driven_ = TableDrivenEnabled(descriptor_, options_);
+ table_driven_ = TableDrivenParsingEnabled(descriptor_, options_);
}
MessageGenerator::~MessageGenerator() {}
@@ -703,24 +713,29 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
}
if (field->is_repeated()) {
- printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n");
+ printer->Print(vars, "$deprecated_attr$int ${$$name$_size$}$() const;\n");
+ printer->Annotate("{", "}", field);
} else if (HasHasMethod(field)) {
- printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n");
+ printer->Print(vars, "$deprecated_attr$bool ${$has_$name$$}$() const;\n");
+ printer->Annotate("{", "}", field);
} else if (HasPrivateHasMethod(field)) {
printer->Print(vars,
- "private:\n"
- "bool has_$name$() const;\n"
- "public:\n");
+ "private:\n"
+ "bool ${$has_$name$$}$() const;\n"
+ "public:\n");
+ printer->Annotate("{", "}", field);
}
if (!dependent_field) {
// If this field is dependent, then its clear_() method is in the
// depenent base class. (See also GenerateDependentAccessorDeclarations.)
- printer->Print(vars, "$deprecated_attr$void clear_$name$();\n");
+ printer->Print(vars, "$deprecated_attr$void ${$clear_$name$$}$();\n");
+ printer->Annotate("{", "}", field);
}
printer->Print(vars,
"$deprecated_attr$static const int $constant_name$ = "
"$number$;\n");
+ printer->Annotate("constant_name", field);
// Generate type-specific accessor declarations.
field_generators_.get(field).GenerateAccessorDeclarations(printer);
@@ -1074,32 +1089,39 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(" public:\n");
printer->Indent();
- printer->Print(vars,
- "$classname$();\n"
- "virtual ~$classname$();\n"
- "\n"
- "$classname$(const $classname$& from);\n"
- "\n"
- "inline $classname$& operator=(const $classname$& from) {\n"
- " CopyFrom(from);\n"
- " return *this;\n"
- "}\n"
- "\n");
+ printer->Print(
+ vars,
+ "$classname$();\n"
+ "virtual ~$classname$();\n"
+ "\n"
+ "$classname$(const $classname$& from);\n"
+ "\n"
+ "inline $classname$& operator=(const $classname$& from) {\n"
+ " CopyFrom(from);\n"
+ " return *this;\n"
+ "}\n");
+
+ if (options_.table_driven_serialization) {
+ printer->Print(
+ "private:\n"
+ "const void* InternalGetTable() const;\n"
+ "public:\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$($classname$&& from) noexcept\n"
" : $classname$() {\n"
" *this = ::std::move(from);\n"
"}\n"
"\n"
- "inline $classname$& operator=($classname$&& from) {\n"
+ "inline $classname$& operator=($classname$&& from) noexcept {\n"
" if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n"
- " InternalSwap(&from);\n"
+ " if (this != &from) InternalSwap(&from);\n"
" } else {\n"
" CopyFrom(from);\n"
" }\n"
@@ -1107,22 +1129,17 @@ GenerateClassDefinition(io::Printer* printer) {
"}\n"
"#endif\n");
}
- #endif
- if (PreserveUnknownFields(descriptor_)) {
- string type = UseUnknownFieldSet(descriptor_->file(), options_)
- ? "::google::protobuf::UnknownFieldSet"
- : "::std::string";
- printer->Print(
- "inline const $type$& unknown_fields() const {\n"
- " return _internal_metadata_.unknown_fields();\n"
- "}\n"
- "\n"
- "inline $type$* mutable_unknown_fields() {\n"
- " return _internal_metadata_.mutable_unknown_fields();\n"
- "}\n"
- "\n",
- "type", type );
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (PublicUnknownFieldsAccessors(descriptor_)) {
+ printer->Print(vars,
+ "inline const $unknown_fields_type$& unknown_fields() const {\n"
+ " return $unknown_fields$;\n"
+ "}\n"
+ "inline $unknown_fields_type$* mutable_unknown_fields() {\n"
+ " return $mutable_unknown_fields$;\n"
+ "}\n"
+ "\n");
}
// N.B.: We exclude GetArena() when arena support is disabled, falling back on
@@ -1190,7 +1207,6 @@ GenerateClassDefinition(io::Printer* printer) {
" $message_index$;\n"
"\n");
-
if (SupportsArenas(descriptor_)) {
printer->Print(vars,
"void UnsafeArenaSwap($classname$* other);\n");
@@ -1214,6 +1230,9 @@ GenerateClassDefinition(io::Printer* printer) {
printer->Print(vars,
"void Swap($classname$* other);\n"
+ "friend void swap($classname$& a, $classname$& b) {\n"
+ " a.Swap(&b);\n"
+ "}\n"
"\n"
"// implements Message ----------------------------------------------\n"
"\n"
@@ -1250,9 +1269,14 @@ GenerateClassDefinition(io::Printer* printer) {
"\n"
"size_t ByteSizeLong() const PROTOBUF_FINAL;\n"
"bool MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"
- "void SerializeWithCachedSizes(\n"
- " ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;\n");
+ " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n");
+ if (!options_.table_driven_serialization ||
+ descriptor_->options().message_set_wire_format()) {
+ printer->Print(
+ "void SerializeWithCachedSizes(\n"
+ " ::google::protobuf::io::CodedOutputStream* output) const "
+ "PROTOBUF_FINAL;\n");
+ }
// DiscardUnknownFields() is implemented in message.cc using reflections. We
// need to implement this function in generated code for messages.
if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
@@ -1278,6 +1302,9 @@ GenerateClassDefinition(io::Printer* printer) {
"final", use_final);
if (SupportsArenas(descriptor_)) {
printer->Print(
+ // TODO(gerbens) Make this private! Currently people are deriving from
+ // protos to give access to this constructor, breaking the invariants
+ // we rely on.
"protected:\n"
"explicit $classname$(::google::protobuf::Arena* arena);\n"
"private:\n"
@@ -1443,7 +1470,7 @@ GenerateClassDefinition(io::Printer* printer) {
if (SupportsArenas(descriptor_)) {
printer->Print(
- "friend class ::google::protobuf::Arena;\n"
+ "template <typename T> friend class ::google::protobuf::Arena::InternalHelper;\n"
"typedef void InternalArenaConstructable_;\n"
"typedef void DestructorSkippable_;\n");
}
@@ -1639,9 +1666,44 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
" $classname$, _has_bits_),\n");
}
+ if (descriptor_->oneof_decl_count() > 0) {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
+ " $classname$, _oneof_case_),\n");
+ } else {
+ printer->Print("-1, // no _oneof_case_\n");
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(vars,
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_extensions_),\n");
+ } else {
+ printer->Print("-1, // no _extensions_\n");
+ }
+
+ // TODO(ckennelly): Consolidate this with the calculation for
+ // AuxillaryParseTableField.
+ std::vector<string> package_parts;
+
+ const Descriptor* outer = descriptor_;
+ while (outer->containing_type() != NULL) {
+ outer = outer->containing_type();
+ }
+
+ package_parts = Split(
+ outer->full_name(), ".", true);
+ // outer->full_name() contains the class itself. Remove it as it is
+ // used in the name of the default instance variable.
+ GOOGLE_DCHECK_NE(package_parts.size(), 0);
+ package_parts.back().clear();
+
+ vars["ns"] = Join(package_parts, "::");
+
printer->Print(vars,
"GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
- " $classname$, _internal_metadata_),\n");
+ " $classname$, _internal_metadata_),\n"
+ "&::$ns$_$classname$_default_instance_,\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
printer->Print(vars, "true,\n");
@@ -1670,6 +1732,239 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
"{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n");
}
+namespace {
+
+// TODO(gerbens) remove this after the next sync with GitHub code base.
+// Then the opensource testing has gained the functionality to compile
+// the CalcFieldNum given the symbols defined in generated-message-util.
+#ifdef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP
+// We need a clean version of CalcFieldNum that doesn't use new functionality
+// in the runtime, because this functionality is not yet in the opensource
+// runtime
+
+uint32 CalculateType(uint32 type, uint32 type_class) {
+ return (type - 1) + type_class * 20;
+}
+
+uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) {
+ bool is_a_map = IsMapEntryMessage(field->containing_type());
+ int type = field->type();
+ if (field->containing_oneof()) {
+ return CalculateType(type, 4);
+ }
+ if (field->is_packed()) {
+ return CalculateType(type, 3);
+ } else if (field->is_repeated()) {
+ return CalculateType(type, 2);
+ } else if (!HasFieldPresence(field->file()) &&
+ field->containing_oneof() == NULL && !is_a_map) {
+ return CalculateType(type, 1);
+ } else {
+ return CalculateType(type, 0);
+ }
+}
+
+#else
+// We need to calculate for each field what function the table driven code
+// should use to serialize it. This returns the index in a lookup table.
+uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) {
+ bool is_a_map = IsMapEntryMessage(field->containing_type());
+ int type = field->type();
+ if (field->containing_oneof()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kOneOf);
+ }
+ if (field->is_packed()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kPacked);
+ } else if (field->is_repeated()) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kRepeated);
+ } else if (!HasFieldPresence(field->file()) &&
+ field->containing_oneof() == NULL && !is_a_map) {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kNoPresence);
+ } else {
+ return internal::FieldMetadata::CalculateType(
+ type, internal::FieldMetadata::kPresence);
+ }
+}
+#endif
+
+int FindMessageIndexInFile(const Descriptor* descriptor) {
+ std::vector<const Descriptor*> flatten =
+ FlattenMessagesInFile(descriptor->file());
+ return std::find(flatten.begin(), flatten.end(), descriptor) -
+ flatten.begin();
+}
+
+} // namespace
+
+int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
+ if (!options_.table_driven_serialization) {
+ return 0;
+ }
+
+ std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_);
+ if (IsMapEntryMessage(descriptor_)) {
+ for (int i = 0; i < 2; i++) {
+ const FieldDescriptor* field = sorted[i];
+ uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormat::WireTypeForFieldType(field->type()));
+
+ std::map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["parent_classname"] =
+ ClassName(descriptor_->containing_type(), false);
+ vars["field_name"] = FieldName(field);
+ vars["tag"] = SimpleItoa(tag);
+ vars["hasbit"] = SimpleItoa(i);
+ vars["type"] = SimpleItoa(CalcFieldNum(field, options_));
+ vars["ptr"] = "NULL";
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ GOOGLE_CHECK(!IsMapEntryMessage(field->message_type()));
+ {
+ vars["ptr"] =
+ QualifiedFileLevelSymbol(
+ field->message_type()->file()->package(),
+ FileLevelNamespace(field->message_type()->file()->name())) +
+ "::TableStruct::serialization_table + " +
+ SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ }
+ }
+ vars["extra"] = HasDescriptorMethods(descriptor_->file(), options_)
+ ? "::SuperType"
+ : "";
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$"
+ "classname$$extra$>, $field_name$_), $tag$,"
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$"
+ "classname$$extra$>, _has_bits_) * 8 + $hasbit$, $type$, "
+ "$ptr$},\n");
+ }
+ return 2;
+ }
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_cached_size_), 0, 0, 0, NULL},\n",
+ "classname", classname_);
+ std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
+ for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+ sorted_extensions.push_back(descriptor_->extension_range(i));
+ }
+ std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+ ExtensionRangeSorter());
+ for (int i = 0, extension_idx = 0; /* no range */; i++) {
+ for (; extension_idx < sorted_extensions.size() &&
+ (i == sorted.size() ||
+ sorted_extensions[extension_idx]->start < sorted[i]->number());
+ extension_idx++) {
+ const Descriptor::ExtensionRange* range =
+ sorted_extensions[extension_idx];
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_extensions_), $start$, $end$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const "
+ "void*>(::google::protobuf::internal::ExtensionSerializer)},\n",
+ "classname", classname_, "start", SimpleItoa(range->start), "end",
+ SimpleItoa(range->end));
+ }
+ if (i == sorted.size()) break;
+ const FieldDescriptor* field = sorted[i];
+
+ uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormat::WireTypeForFieldType(field->type()));
+ if (field->is_packed()) {
+ tag = internal::WireFormatLite::MakeTag(
+ field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ }
+
+ string classfieldname = FieldName(field);
+ if (field->containing_oneof()) {
+ classfieldname = field->containing_oneof()->name();
+ }
+ std::map<string, string> vars;
+ vars["classname"] = classname_;
+ vars["field_name"] = classfieldname;
+ vars["tag"] = SimpleItoa(tag);
+ vars["ptr"] = "NULL";
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (IsMapEntryMessage(field->message_type())) {
+ vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ vars["fieldclassname"] = ClassName(field->message_type(), false);
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, $idx$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const void*>(static_cast< "
+ "::google::protobuf::internal::SpecialSerializer>("
+ "::google::protobuf::internal::MapFieldSerializer< "
+ "::google::protobuf::internal::MapEntryToMapField<$classname$::$"
+ "fieldclassname$>::MapFieldType, "
+ "TableStruct::serialization_table>))},\n");
+ continue;
+ } else {
+ vars["ptr"] =
+ QualifiedFileLevelSymbol(
+ field->message_type()->file()->package(),
+ FileLevelNamespace(field->message_type()->file()->name())) +
+ "::TableStruct::serialization_table + " +
+ SimpleItoa(FindMessageIndexInFile(field->message_type()));
+ }
+ }
+ vars["type"] = SimpleItoa(CalcFieldNum(field, options_));
+
+
+ if (field->options().weak()) {
+ // TODO(gerbens) merge weak fields into ranges
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _weak_field_map_), $tag$, $tag$, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, "
+ "reinterpret_cast<const "
+ "void*>(::google::protobuf::internal::WeakFieldSerializer)},\n");
+ } else if (field->containing_oneof()) {
+ vars["oneofoffset"] =
+ SimpleItoa(sizeof(uint32) * field->containing_oneof()->index());
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, "
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _oneof_case_) + $oneofoffset$, "
+ "$type$, $ptr$},\n");
+ } else if (HasFieldPresence(descriptor_->file()) &&
+ has_bit_indices_[field->index()] != -1) {
+ vars["hasbitsoffset"] = SimpleItoa(has_bit_indices_[field->index()]);
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, "
+ "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, _has_bits_) * 8 + $hasbitsoffset$, $type$, "
+ "$ptr$},\n");
+ } else {
+ printer->Print(vars,
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($"
+ "classname$, $field_name$_), $tag$, ~0u, $type$, "
+ "$ptr$},\n");
+ }
+ }
+ int num_field_metadata = 1 + sorted.size() + sorted_extensions.size();
+ num_field_metadata++;
+ string serializer = UseUnknownFieldSet(descriptor_->file(), options_)
+ ? "::google::protobuf::internal::UnknownFieldSetSerializer"
+ : "::google::protobuf::internal::UnknownFieldSerializerLite";
+ printer->Print(
+ "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, "
+ "_internal_metadata_), 0, ~0u, "
+ "::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const "
+ "void*>($serializer$)},\n",
+ "classname", classname_, "serializer", serializer);
+ return num_field_metadata;
+}
+
void MessageGenerator::
GenerateDefaultInstanceAllocator(io::Printer* printer) {
// Construct the default instances of all fields, as they will be used
@@ -1732,25 +2027,6 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
}
void MessageGenerator::
-GenerateShutdownCode(io::Printer* printer) {
- if (IsMapEntryMessage(descriptor_)) return;
-
- printer->Print("_$classname$_default_instance_.Shutdown();\n", "classname",
- classname_);
-
- if (HasDescriptorMethods(descriptor_->file(), options_)) {
- printer->Print("delete file_level_metadata[$index$].reflection;\n", "index",
- SimpleItoa(index_in_file_messages_));
- }
-
- // Handle default instances of fields.
- for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(descriptor_->field(i))
- .GenerateShutdownCode(printer);
- }
-}
-
-void MessageGenerator::
GenerateClassMethods(io::Printer* printer) {
if (IsMapEntryMessage(descriptor_)) {
if (HasDescriptorMethods(descriptor_->file(), options_)) {
@@ -1854,6 +2130,15 @@ GenerateClassMethods(io::Printer* printer) {
GenerateSwap(printer);
printer->Print("\n");
+ if (options_.table_driven_serialization) {
+ printer->Print(
+ "const void* $classname$::InternalGetTable() const {\n"
+ " return $file_namespace$::TableStruct::serialization_table + $index$;\n"
+ "}\n"
+ "\n",
+ "classname", classname_, "index", SimpleItoa(index_in_file_messages_),
+ "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ }
if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(
"::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
@@ -1926,13 +2211,25 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
processing_type |= static_cast<unsigned>(
field->is_repeated() ? internal::kRepeatedMask : 0);
+ processing_type |= static_cast<unsigned>(
+ field->containing_oneof() ? internal::kOneofMask : 0);
+
+ if (field->is_map()) {
+ processing_type = internal::TYPE_MAP;
+ }
+
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()]);
+ if (field->containing_oneof() != NULL) {
+ vars["name"] = field->containing_oneof()->name();
+ vars["presence"] = SimpleItoa(field->containing_oneof()->index());
+ } else {
+ vars["name"] = FieldName(field);
+ vars["presence"] = SimpleItoa(has_bit_indices_[field->index()]);
+ }
vars["nwtype"] = SimpleItoa(normal_wiretype);
vars["pwtype"] = SimpleItoa(packed_wiretype);
vars["ptype"] = SimpleItoa(processing_type);
@@ -1942,7 +2239,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
"{\n"
" GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n"
" $classname$, $name$_),\n"
- " static_cast< ::google::protobuf::uint32>($has$),\n"
+ " static_cast< ::google::protobuf::uint32>($presence$),\n"
" $nwtype$, $pwtype$, $ptype$, $tag_size$\n"
"},\n");
}
@@ -1977,7 +2274,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
printer->Print(
vars,
"{::google::protobuf::internal::AuxillaryParseTableField::enum_aux{"
- "$type$_IsValid, \"$type$\" }},\n");
+ "$type$_IsValid}},\n");
last_field_number++;
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
@@ -1995,7 +2292,17 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
GOOGLE_DCHECK_NE(package_parts.size(), 0);
package_parts.back().clear();
- vars["classname"] = ClassName(field->message_type(), false);
+ if (field->is_map()) {
+ vars["classname"] = ClassName(field->containing_type(), false) +
+ "::" + ClassName(field->message_type(), false);
+ printer->Print(vars,
+ "{::google::protobuf::internal::AuxillaryParseTableField::map_"
+ "aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n");
+ last_field_number++;
+ break;
+ } else {
+ vars["classname"] = ClassName(field->message_type(), false);
+ }
vars["ns"] = Join(package_parts, "::");
vars["type"] = FieldMessageTypeName(field);
vars["file_namespace"] = FileLevelNamespace(outer->file()->name());
@@ -2005,7 +2312,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
" &::$ns$_$classname$_default_instance_,\n");
bool dont_emit_table =
- !TableDrivenEnabled(field->message_type(), options_);
+ !TableDrivenParsingEnabled(field->message_type(), options_);
if (dont_emit_table) {
printer->Print(" NULL,\n");
@@ -2034,16 +2341,10 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
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"
+ " \"$full_name$\"\n"
"}},\n");
last_field_number++;
break;
@@ -2103,8 +2404,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
const FieldDescriptor* field = descriptor_->field(i);
if (field->containing_oneof() || field->options().weak()) {
printer->Print(
- "GOOGLE_PROTOBUF_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET("
- "(&_$classname$_default_instance_), $name$_),\n",
+ "offsetof($classname$DefaultTypeInternal, $name$_),\n",
"classname", classname_, "name", FieldName(field));
} else {
printer->Print(
@@ -2178,6 +2478,7 @@ GenerateSharedDestructorCode(io::Printer* printer) {
// Do nothing when the message is allocated in an arena.
printer->Print(
"::google::protobuf::Arena* arena = GetArenaNoVirtual();\n"
+ "GOOGLE_DCHECK(arena == NULL);\n"
"if (arena != NULL) {\n"
" return;\n"
"}\n"
@@ -2384,8 +2685,7 @@ GenerateStructors(io::Printer* printer) {
initializer_with_arena += ", _weak_field_map_(arena)";
}
- string initializer_null;
- initializer_null = ", _internal_metadata_(NULL)";
+ string initializer_null = superclass + "(), _internal_metadata_(NULL)";
if (IsAnyMessage(descriptor_)) {
initializer_null += ", _any_metadata_(&type_url_, &value_)";
}
@@ -2395,26 +2695,22 @@ GenerateStructors(io::Printer* printer) {
printer->Print(
"$classname$::$classname$()\n"
- " : $superclass$()$initializer$ {\n"
+ " : $initializer$ {\n"
" if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n"
" $file_namespace$::InitDefaults();\n"
" }\n"
" SharedCtor();\n"
" // @@protoc_insertion_point(constructor:$full_name$)\n"
"}\n",
- "classname", classname_, "superclass", superclass, "full_name",
- descriptor_->full_name(), "initializer", initializer_null,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "classname", classname_, "full_name", descriptor_->full_name(),
+ "initializer", initializer_null, "file_namespace",
+ FileLevelNamespace(descriptor_->file()->name()));
if (SupportsArenas(descriptor_)) {
printer->Print(
"$classname$::$classname$(::google::protobuf::Arena* arena)\n"
" : $initializer$ {\n"
- // When arenas are used it's safe to assume we have finished
- // static init time (protos with arenas are unsafe during static init)
- "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
" $file_namespace$::InitDefaults();\n"
- "#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
" SharedCtor();\n"
" RegisterArenaDtor(arena);\n"
" // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
@@ -2601,7 +2897,6 @@ GenerateStructors(io::Printer* printer) {
"}\n",
"classname", classname_);
}
-
}
// Return the number of bits set in n, a non-negative integer.
@@ -2614,6 +2909,22 @@ static int popcnt(uint32 n) {
return result;
}
+bool MessageGenerator::MaybeGenerateOptionalFieldCondition(
+ io::Printer* printer, const FieldDescriptor* field,
+ int expected_has_bits_index) {
+ int has_bit_index = has_bit_indices_[field->index()];
+ if (!field->options().weak() &&
+ expected_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);
+ return true;
+ }
+ return false;
+}
+
void MessageGenerator::
GenerateClear(io::Printer* printer) {
printer->Print(
@@ -2622,6 +2933,15 @@ GenerateClear(io::Printer* printer) {
"classname", classname_, "full_name", descriptor_->full_name());
printer->Indent();
+ printer->Print(
+ // TODO(jwb): It would be better to avoid emitting this if it is not used,
+ // rather than emitting a workaround for the resulting warning.
+ "::google::protobuf::uint32 cached_has_bits = 0;\n"
+ "// Prevent compiler warnings about cached_has_bits being unused\n"
+ "(void) cached_has_bits;\n\n");
+
+ int cached_has_bit_index = -1;
+
// Step 1: Extensions
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Clear();\n");
@@ -2730,9 +3050,14 @@ GenerateClear(io::Printer* printer) {
GOOGLE_DCHECK_LE(2, count);
GOOGLE_DCHECK_GE(8, count);
+ if (cached_has_bit_index != last_chunk / 4) {
+ cached_has_bit_index = last_chunk / 4;
+ printer->Print(
+ "cached_has_bits = _has_bits_[$idx$];\n",
+ "idx", SimpleItoa(cached_has_bit_index));
+ }
printer->Print(
- "if (_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();
}
@@ -2778,7 +3103,12 @@ GenerateClear(io::Printer* printer) {
if (should_check_bit &&
// If no field presence, then always clear strings/messages as well.
HasFieldPresence(descriptor_->file())) {
- printer->Print("if (has_$name$()) {\n", "name", fieldname);
+ if (!MaybeGenerateOptionalFieldCondition(printer, field,
+ cached_has_bit_index)) {
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", fieldname);
+ }
printer->Indent();
have_enclosing_if = true;
}
@@ -2814,9 +3144,7 @@ GenerateClear(io::Printer* printer) {
printer->Print("_has_bits_.Clear();\n");
}
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print("_internal_metadata_.Clear();\n");
- }
+ printer->Print("_internal_metadata_.Clear();\n");
printer->Outdent();
printer->Print("}\n");
@@ -2920,6 +3248,7 @@ GenerateSwap(io::Printer* printer) {
printer->Print("void $classname$::InternalSwap($classname$* other) {\n",
"classname", classname_);
printer->Indent();
+ printer->Print("using std::swap;\n");
if (HasGeneratedMethods(descriptor_->file(), options_)) {
for (int i = 0; i < optimized_order_.size(); i++) {
@@ -2931,24 +3260,22 @@ GenerateSwap(io::Printer* printer) {
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
- "std::swap($oneof_name$_, other->$oneof_name$_);\n"
- "std::swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n",
+ "swap($oneof_name$_, other->$oneof_name$_);\n"
+ "swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n",
"oneof_name", descriptor_->oneof_decl(i)->name(),
"i", SimpleItoa(i));
}
if (HasFieldPresence(descriptor_->file())) {
for (int i = 0; i < HasBitsSize() / 4; ++i) {
- printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
+ printer->Print("swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
"i", SimpleItoa(i));
}
}
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n");
- }
+ printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n");
- printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
+ printer->Print("swap(_cached_size_, other->_cached_size_);\n");
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Swap(&other->_extensions_);\n");
}
@@ -3251,21 +3578,16 @@ GenerateCopyFrom(io::Printer* printer) {
void MessageGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) {
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
- printer->Print(
+ vars["classname"] = classname_;
+ printer->Print(vars,
"bool $classname$::MergePartialFromCodedStream(\n"
- " ::google::protobuf::io::CodedInputStream* input) {\n",
- "classname", classname_);
-
- printer->Print(
- " return _extensions_.ParseMessageSet(input, "
- "internal_default_instance(),\n"
- " mutable_unknown_fields());\n",
- // Vars.
- "classname", classname_);
-
- printer->Print(
+ " ::google::protobuf::io::CodedInputStream* input) {\n"
+ " return _extensions_.ParseMessageSet(input,\n"
+ " internal_default_instance(), $mutable_unknown_fields$);\n"
"}\n");
return;
}
@@ -3281,14 +3603,18 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
if (table_driven_) {
printer->Indent();
+ const string lite = UseUnknownFieldSet(descriptor_->file(), options_) ?
+ "" : "Lite";
+
printer->Print(
- "return ::google::protobuf::internal::MergePartialFromCodedStream(\n"
+ "return ::google::protobuf::internal::MergePartialFromCodedStream$lite$(\n"
" this,\n"
" $file_namespace$::TableStruct::schema[\n"
" $classname$::kIndexInFileMessages],\n"
" input);\n",
"classname", classname_,
- "file_namespace", FileLevelNamespace(descriptor_->file()->name()));
+ "file_namespace", FileLevelNamespace(descriptor_->file()->name()),
+ "lite", lite);
printer->Outdent();
@@ -3300,8 +3626,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
"#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
" ::google::protobuf::uint32 tag;\n");
- if (PreserveUnknownFields(descriptor_) &&
- !UseUnknownFieldSet(descriptor_->file(), options_)) {
+ if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
// Use LazyStringOutputString to avoid initializing unknown fields string
// unless it is actually needed. For the same reason, disable eager refresh
// on the CodedOutputStream.
@@ -3354,13 +3679,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = "
- "input->ReadTagWithCutoff$lasttag$($max$u);\n"
+ "input->ReadTagWithCutoffNoLastTag($max$u);\n"
"tag = p.first;\n"
"if (!p.second) goto handle_unusual;\n",
"max", SimpleItoa(maxtag <= kCutoff0 ? kCutoff0 :
(maxtag <= kCutoff1 ? kCutoff1 :
- maxtag)),
- "lasttag", !capture_last_tag ? "NoLastTag" : "");
+ maxtag)));
if (descriptor_->field_count() > 0) {
// We don't even want to print the switch() if we have no fields because
@@ -3395,9 +3719,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
const FieldGenerator& field_generator = field_generators_.get(field);
// 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)));
+ printer->Print(
+ "if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(WireFormat::MakeTag(field) & 0xFF),
+ "full", SimpleItoa(WireFormat::MakeTag(field)));
printer->Indent();
if (field->is_packed()) {
@@ -3411,22 +3737,30 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
if (field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
WireFormat::WireTypeForFieldType(field->type());
- printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
- " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n",
- "uncommontag", SimpleItoa(
- internal::WireFormatLite::MakeTag(
- field->number(), wiretype)));
+ const uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), wiretype);
+ printer->Print(
+ "} else if (\n"
+ " static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(tag & 0xFF),
+ "full", SimpleItoa(tag));
+
printer->Indent();
field_generator.GenerateMergeFromCodedStream(printer);
printer->Outdent();
} else if (field->is_packable() && !field->is_packed()) {
internal::WireFormatLite::WireType wiretype =
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
- printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n"
- " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n",
- "uncommontag", SimpleItoa(
- internal::WireFormatLite::MakeTag(
- field->number(), wiretype)));
+ const uint32 tag = internal::WireFormatLite::MakeTag(
+ field->number(), wiretype);
+
+ printer->Print(
+ "} else if (\n"
+ " static_cast< ::google::protobuf::uint8>(tag) ==\n"
+ " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n",
+ "truncated", SimpleItoa(tag & 0xFF),
+ "full", SimpleItoa(tag));
printer->Indent();
field_generator.GenerateMergeFromCodedStreamWithPacking(printer);
printer->Outdent();
@@ -3452,12 +3786,20 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("handle_unusual:\n");
printer->Indent();
// If tag is 0 or an end-group tag then this must be the end of the message.
- printer->Print(
- "if (tag == 0 ||\n"
- " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
- " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
- " goto success;\n"
- "}\n");
+ if (capture_last_tag) {
+ printer->Print(
+ "if (tag == 0 ||\n"
+ " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
+ " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
+ " input->SetLastTag(tag);\n"
+ " goto success;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "if (tag == 0) {\n"
+ " goto success;\n"
+ "}\n");
+ }
// Handle extension ranges.
if (descriptor_->extension_range_count() > 0) {
@@ -3485,23 +3827,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
}
printer->Print(") {\n");
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance(),\n"
- " mutable_unknown_fields()));\n");
- } else {
- printer->Print(
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance(),\n"
- " &unknown_fields_stream));\n");
- }
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ " DO_(_extensions_.ParseField(tag, input,\n"
+ " internal_default_instance(),\n"
+ " $mutable_unknown_fields$));\n");
} else {
printer->Print(
- // With static initializers.
- " DO_(_extensions_.ParseField(tag, input, "
- "internal_default_instance());\n");
+ " DO_(_extensions_.ParseField(tag, input,\n"
+ " internal_default_instance(),\n"
+ " &unknown_fields_stream));\n");
}
printer->Print(
" continue;\n"
@@ -3509,19 +3844,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
// We really don't recognize this tag. Skip it.
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
"DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
- " input, tag, mutable_unknown_fields()));\n");
- } else {
- printer->Print(
- "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
- " input, tag, &unknown_fields_stream));\n");
- }
+ " input, tag, $mutable_unknown_fields$));\n");
} else {
printer->Print(
- "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
+ "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
+ " input, tag, &unknown_fields_stream));\n");
}
if (descriptor_->field_count() > 0) {
@@ -3658,13 +3988,16 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
" _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ printer->Print(vars,
" ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
- " unknown_fields(), output);\n");
+ " $unknown_fields$, output);\n");
printer->Print(
"}\n");
return;
}
+ if (options_.table_driven_serialization) return;
printer->Print(
"void $classname$::SerializeWithCachedSizes(\n"
@@ -3699,10 +4032,12 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
" deterministic, target);\n",
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ printer->Print(vars,
" target = ::google::protobuf::internal::WireFormat::\n"
" SerializeUnknownMessageSetItemsToArray(\n"
- " unknown_fields(), target);\n");
+ " $unknown_fields$, target);\n");
printer->Print(
" return target;\n"
"}\n");
@@ -3866,29 +4201,29 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
}
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n");
- printer->Indent();
- if (to_array) {
- printer->Print(
- "target = "
- "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
- " unknown_fields(), target);\n");
- } else {
- printer->Print(
- "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
- " unknown_fields(), output);\n");
- }
- printer->Outdent();
-
- printer->Print(
- "}\n");
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ "if ($have_unknown_fields$) {\n");
+ printer->Indent();
+ if (to_array) {
+ printer->Print(vars,
+ "target = "
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
+ " $unknown_fields$, target);\n");
} else {
- printer->Print(
- "output->WriteRaw(unknown_fields().data(),\n"
- " static_cast<int>(unknown_fields().size()));\n");
+ printer->Print(vars,
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+ " $unknown_fields$, output);\n");
}
+ printer->Outdent();
+
+ printer->Print("}\n");
+ } else {
+ printer->Print(vars,
+ "output->WriteRaw($unknown_fields$.data(),\n"
+ " static_cast<int>($unknown_fields$.size()));\n");
}
}
@@ -3932,18 +4267,19 @@ void MessageGenerator::
GenerateByteSize(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
- printer->Print(
- "size_t $classname$::ByteSizeLong() const {\n"
- "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
- " size_t total_size = _extensions_.MessageSetByteSize();\n",
- "classname", classname_, "full_name", descriptor_->full_name());
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
- printer->Print(
- "if (_internal_metadata_.have_unknown_fields()) {\n"
- " total_size += ::google::protobuf::internal::WireFormat::\n"
- " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"
- "}\n");
- printer->Print(
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ vars["classname"] = classname_;
+ vars["full_name"] = descriptor_->full_name();
+ printer->Print(vars,
+ "size_t $classname$::ByteSizeLong() const {\n"
+ "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
+ " size_t total_size = _extensions_.MessageSetByteSize();\n"
+ " if ($have_unknown_fields$) {\n"
+ " total_size += ::google::protobuf::internal::WireFormat::\n"
+ " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n"
+ " }\n"
" int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n"
" GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
" _cached_size_ = cached_size;\n"
@@ -3997,19 +4333,19 @@ GenerateByteSize(io::Printer* printer) {
"\n");
}
- if (PreserveUnknownFields(descriptor_)) {
- if (UseUnknownFieldSet(descriptor_->file(), options_)) {
- printer->Print(
- "if (_internal_metadata_.have_unknown_fields()) {\n"
- " total_size +=\n"
- " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
- " unknown_fields());\n"
- "}\n");
- } else {
- printer->Print(
- "total_size += unknown_fields().size();\n"
- "\n");
- }
+ std::map<string, string> vars;
+ SetUnknkownFieldsVariable(descriptor_, options_, &vars);
+ if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+ printer->Print(vars,
+ "if ($have_unknown_fields$) {\n"
+ " total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+ " $unknown_fields$);\n"
+ "}\n");
+ } else {
+ printer->Print(vars,
+ "total_size += $unknown_fields$.size();\n"
+ "\n");
}
// Handle required fields (if any). We expect all of them to be
@@ -4358,7 +4694,6 @@ GenerateIsInitialized(io::Printer* printer) {
"}\n");
}
-
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 23aaeeb0..352069eb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -104,10 +104,6 @@ class MessageGenerator {
// allocated before any can be initialized.
void GenerateDefaultInstanceInitializer(io::Printer* printer);
- // Generates code that should be run when ShutdownProtobufLibrary() is called,
- // to delete all dynamically-allocated objects.
- void GenerateShutdownCode(io::Printer* printer);
-
// Generate all non-inline methods for this class.
void GenerateClassMethods(io::Printer* printer);
@@ -132,6 +128,9 @@ class MessageGenerator {
// of entries generated and the index of the first has_bit entry.
std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
void GenerateSchema(io::Printer* printer, int offset, int has_offset);
+ // For each field generates a table entry describing the field for the
+ // table driven serializer.
+ int GenerateFieldMetadata(io::Printer* printer);
// Generate constructors and destructor.
void GenerateStructors(io::Printer* printer);
@@ -147,6 +146,13 @@ class MessageGenerator {
// Generate the arena-specific destructor code.
void GenerateArenaDestructorCode(io::Printer* printer);
+ // Helper for GenerateClear and others. Optionally emits a condition that
+ // assumes the existence of the cached_has_bits variable, and returns true if
+ // the condition was printed.
+ bool MaybeGenerateOptionalFieldCondition(io::Printer* printer,
+ const FieldDescriptor* field,
+ int expected_has_bits_index);
+
// Generate standard Message methods.
void GenerateClear(io::Printer* printer);
void GenerateOneofClear(io::Printer* printer);
@@ -179,7 +185,6 @@ class MessageGenerator {
io::Printer* printer, const Descriptor::ExtensionRange* range,
bool unbounded);
-
// Generates has_foo() functions and variables for singular field has-bits.
void GenerateSingularFieldHasBits(const FieldDescriptor* field,
std::map<string, string> vars,
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index fc3c4564..e45470fb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -50,6 +50,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
+ (*variables)["type_default_instance"] =
+ DefaultInstanceName(descriptor->message_type());
if (descriptor->options().weak() || !descriptor->containing_oneof()) {
(*variables)["non_null_ptr_to_name"] =
StrCat("this->", (*variables)["name"], "_");
@@ -98,6 +100,7 @@ void MessageFieldGenerator::
GenerateGetterDeclaration(io::Printer* printer) const {
printer->Print(variables_,
"$deprecated_attr$const $type$& $name$() const;\n");
+ printer->Annotate("name", descriptor_);
}
void MessageFieldGenerator::
@@ -107,9 +110,14 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const {
}
// Arena manipulation code is out-of-line in the derived message class.
printer->Print(variables_,
- "$deprecated_attr$$type$* mutable_$name$();\n"
- "$deprecated_attr$$type$* $release_name$();\n"
- "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n");
+ "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n");
+ printer->Annotate("release_name", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$set_allocated_$name$$}$"
+ "($type$* $name$);\n");
+ printer->Annotate("{", "}", descriptor_);
}
void MessageFieldGenerator::
@@ -130,15 +138,25 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
GenerateGetterDeclaration(printer);
if (!dependent_field_) {
printer->Print(variables_,
- "$deprecated_attr$$type$* mutable_$name$();\n"
- "$deprecated_attr$$type$* $release_name$();\n"
- "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n");
+ "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n");
+ printer->Annotate("release_name", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$set_allocated_$name$$}$"
+ "($type$* $name$);\n");
+ printer->Annotate("{", "}", descriptor_);
}
if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ variables_,
+ "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$$type$* unsafe_arena_release_$name$();\n"
- "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n"
- " $type$* $name$);\n");
+ "$deprecated_attr$void "
+ "${$unsafe_arena_set_allocated_$name$$}$(\n"
+ " $type$* $name$);\n");
+ printer->Annotate("{", "}", descriptor_);
}
}
@@ -346,30 +364,18 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer,
bool is_inline) const {
- if (dependent_field_) {
- // for dependent fields we cannot access its internal_default_instance,
- // because the type is incomplete.
- // TODO(gerbens) deprecate dependent base class.
- std::map<string, string> variables(variables_);
- variables["inline"] = is_inline ? "inline " : "";
- printer->Print(variables,
- "$inline$const $type$& $classname$::$name$() const {\n"
- " // @@protoc_insertion_point(field_get:$full_name$)\n"
- " return $name$_ != NULL ? *$name$_\n"
- " : *internal_default_instance()->$name$_;\n"
- "}\n");
- return;
- }
-
std::map<string, string> variables(variables_);
variables["inline"] = is_inline ? "inline " : "";
printer->Print(variables,
"$inline$const $type$& $classname$::$name$() const {\n"
+ " const $type$* p = $name$_;\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
- " return $name$_ != NULL ? *$name$_\n"
- " : *$type$::internal_default_instance();\n"
+ " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n"
+ " &$type_default_instance$);\n"
"}\n");
+ if (dependent_field_) return;
+
if (SupportsArenas(descriptor_)) {
printer->Print(variables,
"$inline$"
@@ -511,18 +517,12 @@ GenerateMergingCode(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+ printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void MessageFieldGenerator::
GenerateDestructorCode(io::Printer* printer) const {
- // In google3 a default instance will never get deleted so we don't need to
- // worry about that but in opensource protobuf default instances are deleted
- // in shutdown process and we need to take special care when handling them.
- printer->Print(variables_,
- "if (this != internal_default_instance()) {\n"
- " delete $name$_;\n"
- "}\n");
+ printer->Print(variables_, "delete $name$_;\n");
}
void MessageFieldGenerator::
@@ -899,16 +899,20 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "$deprecated_attr$$type$* mutable_$name$(int index);\n"
- "$deprecated_attr$$type$* add_$name$();\n");
+ "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
if (dependent_getter_) {
printer->Print(variables_,
"$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
" $name$() const;\n");
+ printer->Annotate("name", descriptor_);
}
printer->Print(variables_,
- "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
- " mutable_$name$();\n");
+ "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
+ " ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
}
void RepeatedMessageFieldGenerator::
@@ -916,6 +920,7 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const {
if (dependent_getter_) {
printer->Print(variables_,
"$deprecated_attr$const $type$& $name$(int index) const;\n");
+ printer->Annotate("name", descriptor_);
}
if (dependent_field_) {
InternalGenerateTypeDependentAccessorDeclarations(printer);
@@ -927,6 +932,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
if (!dependent_getter_) {
printer->Print(variables_,
"$deprecated_attr$const $type$& $name$(int index) const;\n");
+ printer->Annotate("name", descriptor_);
}
if (!dependent_field_) {
InternalGenerateTypeDependentAccessorDeclarations(printer);
@@ -935,6 +941,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
" $name$() const;\n");
+ printer->Annotate("name", descriptor_);
}
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc
new file mode 100644
index 00000000..f72a7d60
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc
@@ -0,0 +1,169 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <gtest/gtest.h>
+
+#if LANG_CXX11
+#include <google/protobuf/stubs/type_traits.h>
+#endif
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace cpp_unittest {
+
+// Moves are enabled only when compiling with a C++11 compiler or newer.
+#if LANG_CXX11
+
+TEST(MovableMessageTest, MoveConstructor) {
+ protobuf_unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+ const auto* nested = &message1.optional_nested_message();
+
+ protobuf_unittest::TestAllTypes message2(std::move(message1));
+ TestUtil::ExpectAllFieldsSet(message2);
+
+ // Check if the optional_nested_message was actually moved (and not just
+ // copied).
+ EXPECT_EQ(nested, &message2.optional_nested_message());
+ EXPECT_NE(nested, &message1.optional_nested_message());
+}
+
+TEST(MovableMessageTest, MoveAssignmentOperator) {
+ protobuf_unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+ const auto* nested = &message1.optional_nested_message();
+
+ protobuf_unittest::TestAllTypes message2;
+ message2 = std::move(message1);
+ TestUtil::ExpectAllFieldsSet(message2);
+
+ // Check if the optional_nested_message was actually moved (and not just
+ // copied).
+ EXPECT_EQ(nested, &message2.optional_nested_message());
+ EXPECT_NE(nested, &message1.optional_nested_message());
+}
+
+TEST(MovableMessageTest, SelfMoveAssignment) {
+ // The `self` reference is necessary to defeat -Wself-move.
+ protobuf_unittest::TestAllTypes message, &self = message;
+ TestUtil::SetAllFields(&message);
+ message = std::move(self);
+ TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(MovableMessageTest, MoveSameArena) {
+ Arena arena;
+
+ auto* message1_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+ TestUtil::SetAllFields(message1_on_arena);
+ const auto* nested = &message1_on_arena->optional_nested_message();
+
+ auto* message2_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+
+ // Moving messages on the same arena should lead to swapped pointers.
+ *message2_on_arena = std::move(*message1_on_arena);
+ EXPECT_EQ(nested, &message2_on_arena->optional_nested_message());
+}
+
+TEST(MovableMessageTest, MoveDifferentArenas) {
+ Arena arena1, arena2;
+
+ auto* message1_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1);
+ TestUtil::SetAllFields(message1_on_arena);
+ const auto* nested = &message1_on_arena->optional_nested_message();
+
+ auto* message2_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2);
+
+ // Moving messages on two different arenas should lead to a copy.
+ *message2_on_arena = std::move(*message1_on_arena);
+ EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
+ TestUtil::ExpectAllFieldsSet(*message1_on_arena);
+ TestUtil::ExpectAllFieldsSet(*message2_on_arena);
+}
+
+TEST(MovableMessageTest, MoveFromArena) {
+ Arena arena;
+
+ auto* message1_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+ TestUtil::SetAllFields(message1_on_arena);
+ const auto* nested = &message1_on_arena->optional_nested_message();
+
+ protobuf_unittest::TestAllTypes message2;
+
+ // Moving from a message on the arena should lead to a copy.
+ message2 = std::move(*message1_on_arena);
+ EXPECT_NE(nested, &message2.optional_nested_message());
+ TestUtil::ExpectAllFieldsSet(*message1_on_arena);
+ TestUtil::ExpectAllFieldsSet(message2);
+}
+
+TEST(MovableMessageTest, MoveToArena) {
+ Arena arena;
+
+ protobuf_unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+ const auto* nested = &message1.optional_nested_message();
+
+ auto* message2_on_arena =
+ Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
+
+ // Moving to a message on the arena should lead to a copy.
+ *message2_on_arena = std::move(message1);
+ EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
+ TestUtil::ExpectAllFieldsSet(message1);
+ TestUtil::ExpectAllFieldsSet(*message2_on_arena);
+}
+
+TEST(MovableMessageTest, Noexcept) {
+ EXPECT_TRUE(
+ std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>());
+ EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>());
+}
+
+#endif // LANG_CXX11
+
+} // namespace cpp_unittest
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index bdaa12a5..04338083 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -49,7 +49,8 @@ struct Options {
transitive_pb_h(true),
annotate_headers(false),
enforce_lite(false),
- table_driven_parsing(false) {}
+ table_driven_parsing(false),
+ table_driven_serialization(false) {}
string dllexport_decl;
bool safe_boundary_check;
@@ -58,6 +59,7 @@ struct Options {
bool annotate_headers;
bool enforce_lite;
bool table_driven_parsing;
+ bool table_driven_serialization;
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 020c1941..07ac0bb4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -115,9 +115,11 @@ GeneratePrivateMembers(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n");
+ printer->Annotate("name", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$$type$ $name$() const;\n"
- "$deprecated_attr$void set_$name$($type$ value);\n");
+ "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
}
void PrimitiveFieldGenerator::
@@ -148,7 +150,7 @@ GenerateMergingCode(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+ printer->Print(variables_, "swap($name$_, other->$name$_);\n");
}
void PrimitiveFieldGenerator::
@@ -290,14 +292,23 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
- "$deprecated_attr$$type$ $name$(int index) const;\n"
- "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
- "$deprecated_attr$void add_$name$($type$ value);\n");
+ "$deprecated_attr$$type$ $name$(int index) const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$add_$name$$}$($type$ value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n"
+ " $name$() const;\n");
+ printer->Annotate("name", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n"
- " $name$() const;\n"
- "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n"
- " mutable_$name$();\n");
+ "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n"
+ " ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
}
void RepeatedPrimitiveFieldGenerator::
@@ -316,8 +327,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
"$inline$void $classname$::add_$name$($type$ value) {\n"
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
- "}\n");
- printer->Print(variables,
+ "}\n"
"$inline$const ::google::protobuf::RepeatedField< $type$ >&\n"
"$classname$::$name$() const {\n"
" // @@protoc_insertion_point(field_list:$full_name$)\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 7a849e2e..c23dd6fd 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -142,28 +142,47 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "$deprecated_attr$const ::std::string& $name$() const;\n"
- "$deprecated_attr$void set_$name$(const ::std::string& value);\n");
+ "$deprecated_attr$const ::std::string& $name$() const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(const ::std::string& value);\n");
+ printer->Annotate("{", "}", descriptor_);
- if (!SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- "#if LANG_CXX11\n"
- "$deprecated_attr$void set_$name$(::std::string&& value);\n"
- "#endif\n");
- }
+ printer->Print(variables_,
+ "#if LANG_CXX11\n"
+ "$deprecated_attr$void ${$set_$name$$}$(::std::string&& value);\n"
+ "#endif\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(const char* value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(const $pointer_type$* "
+ "value, size_t size)"
+ ";\n");
+ printer->Annotate("{", "}", descriptor_);
printer->Print(variables_,
- "$deprecated_attr$void set_$name$(const char* value);\n"
- "$deprecated_attr$void set_$name$(const $pointer_type$* value, size_t size)"
- ";\n"
- "$deprecated_attr$::std::string* mutable_$name$();\n"
- "$deprecated_attr$::std::string* $release_name$();\n"
- "$deprecated_attr$void set_allocated_$name$(::std::string* $name$);\n");
+ "$deprecated_attr$::std::string* ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_, "$deprecated_attr$::std::string* $release_name$();\n");
+ printer->Annotate("release_name", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$set_allocated_$name$$}$(::std::string* $name$);\n");
+ printer->Annotate("{", "}", descriptor_);
if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- "$deprecated_attr$::std::string* unsafe_arena_release_$name$();\n"
- "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n"
- " ::std::string* $name$);\n");
+ printer->Print(
+ variables_,
+ "$deprecated_attr$::std::string* ${$unsafe_arena_release_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$unsafe_arena_set_allocated_$name$$}$(\n"
+ " ::std::string* $name$);\n");
+ printer->Annotate("{", "}", descriptor_);
}
@@ -191,6 +210,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
+ "#if LANG_CXX11\n"
+ "$inline$void $classname$::set_$name$(::std::string&& value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set(\n"
+ " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
+ "}\n"
+ "#endif\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
" $null_check$"
" $set_hasbit$\n"
@@ -456,15 +483,10 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) const {
printer->Print(variables_,
"$classname$::$default_variable_name$.DefaultConstruct();\n"
"*$classname$::$default_variable_name$.get_mutable() = "
- "::std::string($default$, $default_length$);\n");
- }
-}
-
-void StringFieldGenerator::
-GenerateShutdownCode(io::Printer* printer) const {
- if (!descriptor_->default_value_string().empty()) {
- printer->Print(variables_,
- "$classname$::$default_variable_name$.Shutdown();\n");
+ "::std::string($default$, $default_length$);\n"
+ "::google::protobuf::internal::OnShutdownDestroyString(\n"
+ " $classname$::$default_variable_name$.get_mutable());\n"
+ );
}
}
@@ -551,6 +573,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
" GetArenaNoVirtual());\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
+ "#if LANG_CXX11\n"
+ "$inline$void $classname$::set_$name$(::std::string&& value) {\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set(\n"
+ " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
+ "}\n"
+ "#endif\n"
"$inline$void $classname$::set_$name$(const char* value) {\n"
" $null_check$"
" if (!has_$name$()) {\n"
@@ -833,28 +868,62 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
- "$deprecated_attr$const ::std::string& $name$(int index) const;\n"
- "$deprecated_attr$::std::string* mutable_$name$(int index);\n"
- "$deprecated_attr$void set_$name$(int index, const ::std::string& value);\n"
- "#if LANG_CXX11\n"
- "$deprecated_attr$void set_$name$(int index, ::std::string&& value);\n"
- "#endif\n"
- "$deprecated_attr$void set_$name$(int index, const char* value);\n"
- ""
- "$deprecated_attr$void set_$name$("
- "int index, const $pointer_type$* value, size_t size);\n"
- "$deprecated_attr$::std::string* add_$name$();\n"
- "$deprecated_attr$void add_$name$(const ::std::string& value);\n"
- "#if LANG_CXX11\n"
- "$deprecated_attr$void add_$name$(::std::string&& value);\n"
- "#endif\n"
- "$deprecated_attr$void add_$name$(const char* value);\n"
- "$deprecated_attr$void add_$name$(const $pointer_type$* value, size_t size)"
- ";\n"
- "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() "
- "const;\n"
- "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+ "$deprecated_attr$const ::std::string& $name$(int index) const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$::std::string* ${$mutable_$name$$}$(int index);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(int index, const "
+ "::std::string& value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "#if LANG_CXX11\n"
+ "$deprecated_attr$void ${$set_$name$$}$(int index, ::std::string&& value);\n"
+ "#endif\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$set_$name$$}$(int index, const "
+ "char* value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ ""
+ "$deprecated_attr$void ${$set_$name$$}$("
+ "int index, const $pointer_type$* value, size_t size);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$::std::string* ${$add_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$add_$name$$}$(const ::std::string& value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "#if LANG_CXX11\n"
+ "$deprecated_attr$void ${$add_$name$$}$(::std::string&& value);\n"
+ "#endif\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$void ${$add_$name$$}$(const char* value);\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$void ${$add_$name$$}$(const $pointer_type$* "
+ "value, size_t size)"
+ ";\n");
+ printer->Annotate("{", "}", descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() "
+ "const;\n");
+ printer->Annotate("name", descriptor_);
+ printer->Print(variables_,
+ "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* "
+ "${$mutable_$name$$}$()"
";\n");
+ printer->Annotate("{", "}", descriptor_);
if (unknown_ctype) {
printer->Outdent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index af263c1a..531252b0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -65,7 +65,6 @@ class StringFieldGenerator : public FieldGenerator {
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
- void GenerateShutdownCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index e56964c7..fdde771b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -576,12 +576,73 @@ TEST(GeneratedMessageTest, SwapWithOther) {
EXPECT_EQ(unittest::TestAllTypes::BAR, message2.repeated_nested_enum(1));
}
-TEST(GeneratedMessageTest, CopyConstructor) {
- unittest::TestAllTypes message1;
+TEST(GeneratedMessageTest, ADLSwap) {
+ unittest::TestAllTypes message1, message2;
TestUtil::SetAllFields(&message1);
- unittest::TestAllTypes message2(message1);
+ // Note the address of one of the repeated fields, to verify it was swapped
+ // rather than copied.
+ const int32* addr = &message1.repeated_int32().Get(0);
+
+ using std::swap;
+ swap(message1, message2);
+
TestUtil::ExpectAllFieldsSet(message2);
+ TestUtil::ExpectClear(message1);
+
+ EXPECT_EQ(addr, &message2.repeated_int32().Get(0));
+}
+
+TEST(GeneratedMessageTest, CopyConstructor) {
+ // All set.
+ {
+ unittest::TestAllTypes message1;
+ TestUtil::SetAllFields(&message1);
+
+ unittest::TestAllTypes message2(message1);
+ TestUtil::ExpectAllFieldsSet(message2);
+ }
+
+ // None set.
+ {
+ unittest::TestAllTypes message1;
+ unittest::TestAllTypes message2(message1);
+
+ EXPECT_FALSE(message1.has_optional_string());
+ EXPECT_FALSE(message2.has_optional_string());
+ EXPECT_EQ(&message1.optional_string(),
+ &message2.optional_string());
+
+ EXPECT_FALSE(message1.has_optional_bytes());
+ EXPECT_FALSE(message2.has_optional_bytes());
+ EXPECT_EQ(&message1.optional_bytes(),
+ &message2.optional_bytes());
+
+ EXPECT_FALSE(message1.has_optional_nested_message());
+ EXPECT_FALSE(message2.has_optional_nested_message());
+ EXPECT_EQ(&message1.optional_nested_message(),
+ &message2.optional_nested_message());
+
+ EXPECT_FALSE(message1.has_optional_foreign_message());
+ EXPECT_FALSE(message2.has_optional_foreign_message());
+ EXPECT_EQ(&message1.optional_foreign_message(),
+ &message2.optional_foreign_message());
+
+ EXPECT_FALSE(message1.has_optional_import_message());
+ EXPECT_FALSE(message2.has_optional_import_message());
+ EXPECT_EQ(&message1.optional_import_message(),
+ &message2.optional_import_message());
+
+ EXPECT_FALSE(message1.has_optional_public_import_message());
+ EXPECT_FALSE(message2.has_optional_public_import_message());
+ EXPECT_EQ(&message1.optional_public_import_message(),
+ &message2.optional_public_import_message());
+
+ EXPECT_FALSE(message1.has_optional_lazy_message());
+ EXPECT_FALSE(message2.has_optional_lazy_message());
+ EXPECT_EQ(&message1.optional_lazy_message(),
+ &message2.optional_lazy_message());
+ }
}
TEST(GeneratedMessageTest, CopyConstructorWithArenas) {
@@ -1340,7 +1401,7 @@ class GeneratedServiceTest : public testing::Test {
foo_(descriptor_->FindMethodByName("Foo")),
bar_(descriptor_->FindMethodByName("Bar")),
stub_(&mock_channel_),
- done_(NewPermanentCallback(&DoNothing)) {}
+ done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {}
virtual void SetUp() {
ASSERT_TRUE(foo_ != NULL);