diff options
author | Adam Cozzette <acozzette@google.com> | 2017-09-12 10:32:01 -0700 |
---|---|---|
committer | Adam Cozzette <acozzette@google.com> | 2017-09-14 10:03:57 -0700 |
commit | 13fd045dbb2b4dacea32be162a41d5a4b0d1802f (patch) | |
tree | c219e7eb18b82523e36c6748861c403a14ea66ae /src/google/protobuf/compiler | |
parent | d1bc27caef8377a710370189675cb0958443e8f1 (diff) |
Integrated internal changes from Google
Diffstat (limited to 'src/google/protobuf/compiler')
43 files changed, 2635 insertions, 2252 deletions
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index dd6a59d8..4b1d90b8 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -51,6 +51,7 @@ class FileDescriptor; namespace compiler { class AccessInfoMap; + class Version; // Defined in this file. @@ -165,7 +166,7 @@ typedef GeneratorContext OutputDirectory; // "foo=bar,baz,qux=corge" // parses to the pairs: // ("foo", "bar"), ("baz", ""), ("qux", "corge") -LIBPROTOC_EXPORT void ParseGeneratorParameter( +void ParseGeneratorParameter( const string&, std::vector<std::pair<string, string> >*); } // namespace compiler diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 5f864041..6c2fc164 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -69,9 +69,6 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/stringprintf.h> -#include <google/protobuf/compiler/importer.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/compiler/plugin.pb.h> #include <google/protobuf/compiler/subprocess.h> #include <google/protobuf/compiler/zip_writer.h> #include <google/protobuf/compiler/plugin.pb.h> @@ -83,16 +80,11 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/text_format.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/io_win32.h> -#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/stl_util.h> +#include <google/protobuf/stubs/io_win32.h> namespace google { @@ -232,7 +224,7 @@ bool IsInstalledProtoPath(const string& path) { return access(file_path.c_str(), F_OK) != -1; } -// Add the paths where google/protobuf/descritor.proto and other well-known +// Add the paths where google/protobuf/descriptor.proto and other well-known // type protos are installed. void AddDefaultProtoPaths(vector<pair<string, string> >* paths) { // TODO(xiaofeng): The code currently only checks relative paths of where @@ -876,6 +868,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { return 1; } + // We construct a separate GeneratorContext for each output location. Note // that two code generators may output to the same location, in which case // they should share a single GeneratorContext so that OpenForInsert() works. @@ -1019,7 +1012,8 @@ bool CommandLineInterface::PopulateSimpleDescriptorDatabase( bool parsed = file_descriptor_set.ParseFromFileDescriptor(fd); if (close(fd) != 0) { std::cerr << descriptor_set_in_names_[i] << ": close: " - << strerror(errno); + << strerror(errno) + << std::endl; return false; } @@ -1172,6 +1166,21 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative( return true; } +bool CommandLineInterface::ExpandArgumentFile(const string& file, + std::vector<string>* arguments) { + // The argument file is searched in the working directory only. We don't + // use the proto import path here. + std::ifstream file_stream(file.c_str()); + if (!file_stream.is_open()) { + return false; + } + string argument; + // We don't support any kind of shell expansion right now. + while (std::getline(file_stream, argument)) { + arguments->push_back(argument); + } + return true; +} CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { @@ -1179,11 +1188,19 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { std::vector<string> arguments; for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '@') { + if (!ExpandArgumentFile(argv[i] + 1, &arguments)) { + std::cerr << "Failed to open argument file: " << (argv[i] + 1) + << std::endl; + return PARSE_ARGUMENT_FAIL; + } + continue; + } arguments.push_back(argv[i]); } // if no arguments are given, show help - if(arguments.empty()) { + if (arguments.empty()) { PrintHelpText(); return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler. } @@ -1749,6 +1766,20 @@ void CommandLineInterface::PrintHelpText() { << string(19 - iter->first.size(), ' ') // Spaces for alignment. << iter->second.help_text << std::endl; } + std::cerr << +" @<filename> Read options and filenames from file. If a\n" +" relative file path is specified, the file\n" +" will be searched in the working directory.\n" +" The --proto_path option will not affect how\n" +" this argument file is searched. Content of\n" +" the file will be expanded in the position of\n" +" @<filename> as in the argument list. Note\n" +" that shell expansion is not applied to the\n" +" content of the file (i.e., you cannot use\n" +" quotes, wildcards, escapes, commands, etc.).\n" +" Each line corresponds to a single argument,\n" +" even if it contains spaces." + << std::endl; } bool CommandLineInterface::GenerateOutput( diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index e6596575..d5d85f2d 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -227,6 +227,9 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Parse all command-line arguments. ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); + // Read an argument file and append the file's content to the list of + // arguments. Return false if the file cannot be read. + bool ExpandArgumentFile(const string& file, std::vector<string>* arguments); // Parses a command-line argument into a name/value pair. Returns // true if the next argument in the argv should be used as the value, diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 73d3e4c9..38d0e388 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -35,6 +35,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> + #ifndef _MSC_VER #include <unistd.h> #endif @@ -84,6 +85,7 @@ using google::protobuf::internal::win32::write; // which case tcmalloc will print warnings that fail the plugin tests. #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN + namespace { bool FileExists(const string& path) { @@ -1559,6 +1561,36 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { } #endif // !_WIN32 +TEST_F(CommandLineInterfaceTest, TestArgumentFile) { + // Test parsing multiple input files using an argument file. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "message Bar {}\n"); + CreateTempFile("arguments.txt", + "--test_out=$tmpdir\n" + "--plug_out=$tmpdir\n" + "--proto_path=$tmpdir\n" + "--direct_dependencies_violation_msg=%s is not imported\n" + "foo.proto\n" + "bar.proto"); + + Run("protocol_compiler @$tmpdir/arguments.txt"); + + ExpectNoErrors(); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto", + "bar.proto", "Bar"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "foo.proto", "Foo"); + ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto", + "bar.proto", "Bar"); +} + // ------------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 3b4b97e6..8adee0f5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -197,6 +197,8 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { vars["nested_name"] = descriptor_->name(); vars["classname"] = classname_; vars["constexpr"] = options_.proto_h ? "constexpr " : ""; + vars["{"] = ""; + vars["}"] = ""; printer->Print(vars, "typedef $classname$ $nested_name$;\n"); for (int j = 0; j < descriptor_->value_count(); j++) { @@ -204,22 +206,27 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : ""; printer->Print(vars, - "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n" + "$deprecated_attr$static $constexpr$const $nested_name$ ${$$tag$$}$ =\n" " $classname$_$tag$;\n"); + printer->Annotate("{", "}", descriptor_->value(j)); } printer->Print(vars, "static inline bool $nested_name$_IsValid(int value) {\n" " return $classname$_IsValid(value);\n" "}\n" - "static const $nested_name$ $nested_name$_MIN =\n" - " $classname$_$nested_name$_MIN;\n" - "static const $nested_name$ $nested_name$_MAX =\n" + "static const $nested_name$ ${$$nested_name$_MIN$}$ =\n" + " $classname$_$nested_name$_MIN;\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(vars, + "static const $nested_name$ ${$$nested_name$_MAX$}$ =\n" " $classname$_$nested_name$_MAX;\n"); + printer->Annotate("{", "}", descriptor_); if (generate_array_size_) { printer->Print(vars, - "static const int $nested_name$_ARRAYSIZE =\n" + "static const int ${$$nested_name$_ARRAYSIZE$}$ =\n" " $classname$_$nested_name$_ARRAYSIZE;\n"); + printer->Annotate("{", "}", descriptor_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -242,27 +249,10 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { } } -void EnumGenerator::GenerateDescriptorInitializer(io::Printer* printer) { - std::map<string, string> vars; - vars["index"] = SimpleItoa(descriptor_->index()); - vars["index_in_metadata"] = SimpleItoa(index_in_metadata_); - - if (descriptor_->containing_type() == NULL) { - printer->Print(vars, - "file_level_enum_descriptors[$index_in_metadata$] = " - "file->enum_type($index$);\n"); - } else { - vars["parent"] = ClassName(descriptor_->containing_type(), false); - printer->Print(vars, - "file_level_enum_descriptors[$index_in_metadata$] = " - "$parent$_descriptor->enum_type($index$);\n"); - } -} - -void EnumGenerator::GenerateMethods(io::Printer* printer) { +void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { std::map<string, string> vars; vars["classname"] = classname_; - vars["index_in_metadata"] = SimpleItoa(index_in_metadata_); + vars["index_in_metadata"] = SimpleItoa(idx); vars["constexpr"] = options_.proto_h ? "constexpr " : ""; vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name()); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 0b568c57..0d2488a9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -86,13 +86,10 @@ class EnumGenerator { // Source file stuff. - // Generate code that initializes the global variable storing the enum's - // descriptor. - void GenerateDescriptorInitializer(io::Printer* printer); - // Generate non-inline methods related to the enum, such as IsValidValue(). - // Goes in the .cc file. - void GenerateMethods(io::Printer* printer); + // Goes in the .cc file. EnumDescriptors are stored in an array, idx is + // the index in this array that corresponds with this enum. + void GenerateMethods(int idx, io::Printer* printer); private: const EnumDescriptor* descriptor_; @@ -101,8 +98,6 @@ class EnumGenerator { // whether to generate the *_ARRAYSIZE constant. const bool generate_array_size_; - int index_in_metadata_; - friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 08a635fa..008490ed 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -232,9 +232,8 @@ GenerateSwappingCode(io::Printer* printer) const { void EnumOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print( - variables_, - "_$classname$_default_instance_.$name$_ = $default$;\n"); + printer->Print(variables_, + "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); } // =================================================================== diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 6b1673b2..0a4e0bb9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -167,46 +167,6 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { " $name$($constant_name$, $default$);\n"); } -void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { - std::map<string, string> vars; - vars["extendee" ] = ExtendeeClassName(descriptor_); - vars["number" ] = SimpleItoa(descriptor_->number()); - vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); - vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; - vars["is_packed" ] = (descriptor_->is_repeated() && - descriptor_->options().packed()) - ? "true" : "false"; - - switch (descriptor_->cpp_type()) { - case FieldDescriptor::CPPTYPE_ENUM: - printer->Print( - vars, - "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" - " $extendee$::internal_default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); - printer->Print( - " &$type$_IsValid);\n", - "type", ClassName(descriptor_->enum_type(), true)); - break; - case FieldDescriptor::CPPTYPE_MESSAGE: - printer->Print( - vars, - "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" - " $extendee$::internal_default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); - printer->Print(" $type$::internal_default_instance());\n", "type", - ClassName(descriptor_->message_type(), true)); - break; - default: - printer->Print( - vars, - "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" - " $extendee$::internal_default_instance(),\n" - " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); - break; - } -} - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index 1c1caf1f..30236d71 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -67,9 +67,6 @@ class ExtensionGenerator { // Source file stuff. void GenerateDefinition(io::Printer* printer); - // Generate code to register the extension. - void GenerateRegistration(io::Printer* printer); - private: const FieldDescriptor* descriptor_; string type_traits_; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index dce9617c..f8e11855 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -61,6 +61,7 @@ using internal::WireFormat; void SetCommonFieldVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables, const Options& options) { + (*variables)["ns"] = Namespace(descriptor); (*variables)["name"] = FieldName(descriptor); (*variables)["index"] = SimpleItoa(descriptor->index()); (*variables)["number"] = SimpleItoa(descriptor->number()); diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index a066a6a7..0e74f215 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -55,70 +55,24 @@ namespace google { namespace protobuf { namespace compiler { namespace cpp { -namespace { -// The list of names that are defined as macros on some platforms. We need to -// #undef them for the generated code to compile. -const char* kMacroNames[] = {"major", "minor"}; - -bool IsMacroName(const string& name) { - // Just do a linear search as the number of elements is very small. - for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) { - if (name == kMacroNames[i]) return true; - } - return false; -} - -void CollectMacroNames(const Descriptor* message, std::vector<string>* names) { - for (int i = 0; i < message->field_count(); ++i) { - const FieldDescriptor* field = message->field(i); - if (IsMacroName(field->name())) { - names->push_back(field->name()); - } - } - for (int i = 0; i < message->nested_type_count(); ++i) { - CollectMacroNames(message->nested_type(i), names); - } -} - -void CollectMacroNames(const FileDescriptor* file, std::vector<string>* names) { - // Only do this for protobuf's own types. There are some google3 protos using - // macros as field names and the generated code compiles after the macro - // expansion. Undefing these macros actually breaks such code. - if (file->name() != "google/protobuf/compiler/plugin.proto") { - return; - } - for (int i = 0; i < file->message_type_count(); ++i) { - CollectMacroNames(file->message_type(i), names); - } -} - - -} // namespace - -// =================================================================== FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), options_(options), scc_analyzer_(options), - message_generators_owner_( - new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]), enum_generators_owner_( new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]), service_generators_owner_( new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]), extension_generators_owner_( new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) { - - for (int i = 0; i < file->message_type_count(); i++) { - message_generators_owner_[i].reset( - new MessageGenerator(file->message_type(i), options, &scc_analyzer_)); - message_generators_owner_[i]->Flatten(&message_generators_); - } - - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->AddGenerators(&enum_generators_, - &extension_generators_); + std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); + for (int i = 0; i < msgs.size(); i++) { + // Deleted in destructor + MessageGenerator* msg_gen = + new MessageGenerator(msgs[i], i, options, &scc_analyzer_); + message_generators_.push_back(msg_gen); + msg_gen->AddGenerators(&enum_generators_, &extension_generators_); } for (int i = 0; i < file->enum_type_count(); i++) { @@ -126,9 +80,6 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) new EnumGenerator(file->enum_type(i), options)); enum_generators_.push_back(enum_generators_owner_[i].get()); } - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->index_in_metadata_ = i; - } for (int i = 0; i < file->service_count(); i++) { service_generators_owner_[i].reset( @@ -147,14 +98,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) extension_generators_.push_back(extension_generators_owner_[i].get()); } + package_parts_ = Split(file_->package(), ".", true); } -FileGenerator::~FileGenerator() {} +FileGenerator::~FileGenerator() { + for (int i = 0; i < message_generators_.size(); i++) { + delete message_generators_[i]; + } +} void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { + // Only do this for protobuf's own types. There are some google3 protos using + // macros as field names and the generated code compiles after the macro + // expansion. Undefing these macros actually breaks such code. + if (file_->name() != "google/protobuf/compiler/plugin.proto") { + return; + } std::vector<string> names_to_undef; - CollectMacroNames(file_, &names_to_undef); + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + for (int i = 0; i < fields.size(); i++) { + const string& name = fields[i]->name(); + static const char* kMacroNames[] = {"major", "minor"}; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kMacroNames); ++i) { + if (name == kMacroNames[i]) { + names_to_undef.push_back(name); + break; + } + } + } for (int i = 0; i < names_to_undef.size(); ++i) { printer->Print( "#ifdef $name$\n" @@ -170,43 +143,41 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { GenerateMacroUndefs(printer); - GenerateForwardDeclarations(printer); - - // Open namespace. - GenerateNamespaceOpeners(printer); - GenerateGlobalStateFunctionDeclarations(printer); - printer->Print("\n"); + GenerateForwardDeclarations(printer); - GenerateEnumDefinitions(printer); + { + NamespaceOpener ns(Namespace(file_), printer); - printer->Print(kThickSeparator); - printer->Print("\n"); + printer->Print("\n"); - GenerateMessageDefinitions(printer); + GenerateEnumDefinitions(printer); - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); - GenerateServiceDefinitions(printer); + GenerateMessageDefinitions(printer); - GenerateExtensionIdentifiers(printer); + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + GenerateServiceDefinitions(printer); - GenerateInlineFunctionDefinitions(printer); + GenerateExtensionIdentifiers(printer); - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n" - "\n"); + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateInlineFunctionDefinitions(printer); - // Close up namespace. - GenerateNamespaceClosers(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); + } // We need to specialize some templates in the ::google::protobuf namespace: GenerateProto2NamespaceEnumSpecializations(printer); @@ -269,15 +240,12 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, // TODO(gerbens) remove this. printer->Print( "// @@protoc_insertion_point(includes)\n"); - - // Open namespace. - GenerateNamespaceOpeners(printer); - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); - // Close up namespace. - GenerateNamespaceClosers(printer); - + { + NamespaceOpener ns(Namespace(file_), printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n" @@ -287,7 +255,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, GenerateBottomHeaderGuard(printer, filename_identifier); } -void FileGenerator::GenerateSource(io::Printer* printer) { +void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { const bool use_system_include = IsWellKnownMessage(file_); string header = StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); @@ -295,9 +263,6 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" - // The generated code calls accessors that might be deprecated. We don't - // want the compiler to warn in generated code. - "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" "#include $left$$header$$right$\n" "\n" "#include <algorithm>\n" // for swap() @@ -340,101 +305,129 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print( "// @@protoc_insertion_point(includes)\n"); +} + +void FileGenerator::GenerateSourceDefaultInstance(int idx, + io::Printer* printer) { + printer->Print( + "class $classname$DefaultTypeInternal {\n" + " public:\n" + " ::google::protobuf::internal::ExplicitlyConstructed<$classname$>\n" + " _instance;\n", + "classname", message_generators_[idx]->classname_); + printer->Indent(); + message_generators_[idx]->GenerateExtraDefaultFields(printer); + printer->Outdent(); + printer->Print("} _$classname$_default_instance_;\n", "classname", + message_generators_[idx]->classname_); +} - GenerateNamespaceOpeners(printer); +namespace { - for (int i = 0; i < message_generators_.size(); i++) { - string parent; - if (IsMapEntryMessage(message_generators_[i]->descriptor_)) { - parent = ClassName(message_generators_[i]->descriptor_->containing_type(), - false) + - "::"; +// Generates weak symbol declarations for types that are to be considered weakly +// referenced. +void GenerateWeakDeclarations( + const FileDescriptor* file, const Options& options, + SCCAnalyzer* scc_analyzer, + io::Printer* printer) { + std::vector<const FieldDescriptor*> fields; + ListAllFields(file, &fields); + + // To ensure determinism and minimize the number of namespace statements, + // we output the forward declarations sorted on namespace and type / function + // name. + std::set<std::pair<string, string> > messages; + std::set<std::pair<string, string> > inits; + for (int i = 0; i < fields.size(); ++i) { + const FieldDescriptor* field = fields[i]; + bool is_weak = IsImplicitWeakField(field, options); + if (is_weak) { + const Descriptor* msg = field->message_type(); + string flns = FileLevelNamespace(msg); + string repr = ClassName(scc_analyzer->GetSCC(msg)->GetRepresentative()); + inits.insert(std::make_pair(flns, "InitDefaults" + repr)); + inits.insert(std::make_pair(flns, "AddDescriptors")); + messages.insert(std::make_pair(Namespace(msg), ClassName(msg))); } - printer->Print( - "class $classname$DefaultTypeInternal {\n" - "public:\n" - " ::google::protobuf::internal::ExplicitlyConstructed<$parent$$classname$>\n" - " _instance;\n", - "parent", parent, "classname", message_generators_[i]->classname_); - printer->Indent(); - message_generators_[i]->GenerateExtraDefaultFields(printer); - printer->Outdent(); - printer->Print( - "} _$classname$_default_instance_;\n", - "classname", message_generators_[i]->classname_); } - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->index_in_metadata_ = i; + if (messages.empty()) { + return; } - if (HasGenericServices(file_, options_)) { - for (int i = 0; i < service_generators_.size(); i++) { - service_generators_[i]->index_in_metadata_ = i; - } + + printer->Print("\n"); + NamespaceOpener ns(printer); + for (std::set<std::pair<string, string> >::const_iterator it = + messages.begin(); + it != messages.end(); ++it) { + ns.ChangeTo(it->first); + printer->Print( + "extern __attribute__((weak)) $classname$DefaultTypeInternal " + "_$classname$_default_instance_;\n", + "classname", it->second); + } + for (std::set<std::pair<string, string> >::const_iterator it = inits.begin(); + it != inits.end(); ++it) { + ns.ChangeTo(it->first); + printer->Print("void $name$() __attribute__((weak));\n", + "name", it->second); } +} - printer->Print( - "\n" - "namespace $file_namespace$ {\n" - "\n", - "file_namespace", FileLevelNamespace(file_->name())); +} // namespace - if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "\n" - "namespace {\n" - "\n"); +void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { + GenerateSourceIncludes(printer); + GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); - if (!message_generators_.empty()) { - printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", - "size", SimpleItoa(message_generators_.size())); - } - if (!enum_generators_.empty()) { - printer->Print( - "const ::google::protobuf::EnumDescriptor* " - "file_level_enum_descriptors[$size$];\n", - "size", SimpleItoa(enum_generators_.size())); - } - if (HasGenericServices(file_, options_) && file_->service_count() > 0) { - printer->Print( - "const ::google::protobuf::ServiceDescriptor* " - "file_level_service_descriptors[$size$];\n", - "size", SimpleItoa(file_->service_count())); - } + { // package namespace + NamespaceOpener ns(Namespace(file_), printer); + + // Define default instances + GenerateSourceDefaultInstance(idx, printer); + + // Generate classes. + printer->Print("\n"); + message_generators_[idx]->GenerateClassMethods(printer); printer->Print( - "\n" - "} // namespace\n" - "\n"); - } + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } // end package namespace - // Define our externally-visible BuildDescriptors() function. (For the lite - // library, all this does is initialize default instances.) - GenerateBuildDescriptors(printer); + if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { + NamespaceOpener ns(FileLevelNamespace(file_), printer); + GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); + } printer->Print( "\n" - "} // namespace $file_namespace$\n" - "\n", - "file_namespace", FileLevelNamespace(file_->name())); + "// @@protoc_insertion_point(global_scope)\n"); +} + +void FileGenerator::GenerateGlobalSource(io::Printer* printer) { + GenerateSourceIncludes(printer); + GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + + // TODO(gerbens) Generate tables here + + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + if (HasDescriptorMethods(file_, options_)) { + NamespaceOpener ns(FileLevelNamespace(file_), printer); + GenerateReflectionInitializationCode(printer); + } + + NamespaceOpener ns(Namespace(file_), printer); // Generate enums. for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateMethods(printer); + enum_generators_[i]->GenerateMethods(i, printer); } - // Generate classes. - for (int i = 0; i < message_generators_.size(); i++) { - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); - message_generators_[i]->GenerateClassMethods(printer); - - printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - // Generate class inline methods. - message_generators_[i]->GenerateInlineMethods(printer, - /* is_inline = */ false); - printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + // Define extensions. + for (int i = 0; i < extension_generators_.size(); i++) { + extension_generators_[i]->GenerateDefinition(printer); } if (HasGenericServices(file_, options_)) { @@ -446,18 +439,76 @@ void FileGenerator::GenerateSource(io::Printer* printer) { service_generators_[i]->GenerateImplementation(printer); } } +} - // Define extensions. - for (int i = 0; i < extension_generators_.size(); i++) { - extension_generators_[i]->GenerateDefinition(printer); +void FileGenerator::GenerateSource(io::Printer* printer) { + GenerateSourceIncludes(printer); + GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + + { + NamespaceOpener ns(Namespace(file_), printer); + + // Define default instances + for (int i = 0; i < message_generators_.size(); i++) { + GenerateSourceDefaultInstance(i, printer); + if (UsingImplicitWeakFields(file_, options_)) { + printer->Print("void $classname$_Reference() {}\n", "classname", + message_generators_[i]->classname_); + } + } } - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + { + NamespaceOpener ns(FileLevelNamespace(file_), printer); + // Define the initialization code to initialize the default instances. + // This code doesn't use a global constructor. + GenerateInitializationCode(printer); - GenerateNamespaceClosers(printer); + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + if (HasDescriptorMethods(file_, options_)) { + GenerateReflectionInitializationCode(printer); + } + } + + + { + NamespaceOpener ns(Namespace(file_), printer); + + // Actually implement the protos + + // Generate enums. + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateMethods(i, printer); + } + // Generate classes. + for (int i = 0; i < message_generators_.size(); i++) { + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + message_generators_[i]->GenerateClassMethods(printer); + } + + if (HasGenericServices(file_, options_)) { + // Generate services. + for (int i = 0; i < service_generators_.size(); i++) { + if (i == 0) printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + service_generators_[i]->GenerateImplementation(printer); + } + } + + // Define extensions. + for (int i = 0; i < extension_generators_.size(); i++) { + extension_generators_[i]->GenerateDefinition(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + } printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n"); @@ -512,6 +563,10 @@ class FileGenerator::ForwardDeclarations { options.dllexport_decl.empty() ? "" : options.dllexport_decl + " ", "classname", it->first); + if (options.lite_implicit_weak_fields) { + printer->Print("void $classname$_Reference();\n", + "classname", it->first); + } } for (std::map<string, ForwardDeclarations *>::const_iterator it = namespaces_.begin(), @@ -532,13 +587,11 @@ class FileGenerator::ForwardDeclarations { std::map<string, const EnumDescriptor*> enums_; }; -void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { +void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for // generated files (DescriptorPool::generated_pool()). It ordinarily runs at - // static initialization time, but is not used at all in LITE_RUNTIME mode - // except when extensions are used. This procedure also constructs default - // instances and registers extensions. + // static initialization time, but is not used at all in LITE_RUNTIME mode. // // Its sibling, AssignDescriptors(), actually pulls the compiled // FileDescriptor from the DescriptorPool and uses it to populate all of @@ -547,172 +600,83 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // anyone calls descriptor() or GetReflection() on one of the types defined // in the file. - // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors() - // and we only use AddDescriptors() to allocate default instances. - - // TODO(ckennelly): Gate this with the same options flag to enable - // table-driven parsing. - - printer->Print("PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n" - " const TableStruct::entries[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); - - std::vector<size_t> entries; - size_t count = 0; - for (int i = 0; i < message_generators_.size(); i++) { - size_t value = message_generators_[i]->GenerateParseOffsets(printer); - entries.push_back(value); - count += value; - } - - // We need these arrays to exist, and MSVC does not like empty arrays. - if (count == 0) { - printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n"); - } - - printer->Outdent(); - printer->Print( - "};\n" - "\n" - "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n" - " const TableStruct::aux[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); - - std::vector<size_t> aux_entries; - count = 0; - for (int i = 0; i < message_generators_.size(); i++) { - size_t value = message_generators_[i]->GenerateParseAuxTable(printer); - aux_entries.push_back(value); - count += value; - } - - if (count == 0) { - printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); + if (!message_generators_.empty()) { + printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", "size", + SimpleItoa(message_generators_.size())); } - - printer->Outdent(); - printer->Print( - "};\n" - "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n" - " TableStruct::schema[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); - - size_t offset = 0; - size_t aux_offset = 0; - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); - offset += entries[i]; - aux_offset += aux_entries[i]; + if (!enum_generators_.empty()) { + printer->Print( + "const ::google::protobuf::EnumDescriptor* " + "file_level_enum_descriptors[$size$];\n", + "size", SimpleItoa(enum_generators_.size())); } - - if (message_generators_.empty()) { - printer->Print("{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },\n"); + if (HasGenericServices(file_, options_) && file_->service_count() > 0) { + printer->Print( + "const ::google::protobuf::ServiceDescriptor* " + "file_level_service_descriptors[$size$];\n", + "size", SimpleItoa(file_->service_count())); } - printer->Outdent(); - printer->Print( - "};\n" - "\n"); - - if (!message_generators_.empty() && options_.table_driven_serialization) { + if (!message_generators_.empty()) { printer->Print( - "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] " - "= {\n"); + "\n" + "const ::google::protobuf::uint32 TableStruct::offsets[] " + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); - std::vector<int> field_metadata_offsets; - int idx = 0; + std::vector<std::pair<size_t, size_t> > pairs; + pairs.reserve(message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { - field_metadata_offsets.push_back(idx); - idx += message_generators_[i]->GenerateFieldMetadata(printer); + pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); } - field_metadata_offsets.push_back(idx); printer->Outdent(); printer->Print( "};\n" - "const ::google::protobuf::internal::SerializationTable " - "TableStruct::serialization_table[] = {\n"); + "static const ::google::protobuf::internal::MigrationSchema schemas[] " + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + printer->Indent(); + { + int offset = 0; + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSchema(printer, offset, + pairs[i].second); + offset += pairs[i].first; + } + } + printer->Outdent(); + printer->Print( + "};\n" + "\nstatic " + "::google::protobuf::Message const * const file_default_instances[] = {\n"); printer->Indent(); - // We rely on the order we layout the tables to match the order we - // calculate them with FlattenMessagesInFile, so we check here that - // these match exactly. - std::vector<const Descriptor*> calculated_order = - FlattenMessagesInFile(file_); - GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { - GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); + const Descriptor* descriptor = message_generators_[i]->descriptor_; printer->Print( - "{$num_fields$, TableStruct::field_metadata + $index$},\n", - "classname", message_generators_[i]->classname_, "num_fields", - SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]), - "index", SimpleItoa(field_metadata_offsets[i])); + "reinterpret_cast<const " + "::google::protobuf::Message*>(&$ns$::_$classname$_default_instance_),\n", + "classname", ClassName(descriptor), "ns", Namespace(descriptor)); } printer->Outdent(); printer->Print( "};\n" "\n"); + } else { + // we still need these symbols to exist + printer->Print( + // MSVC doesn't like empty arrays, so we add a dummy. + "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n" + "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" + "static const ::google::protobuf::Message* const* " + "file_default_instances = NULL;\n" + "\n"); } - if (HasDescriptorMethods(file_, options_)) { - if (!message_generators_.empty()) { - printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); - std::vector<std::pair<size_t, size_t> > pairs; - for (int i = 0; i < message_generators_.size(); i++) { - pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); - } - printer->Outdent(); - printer->Print( - "};\n" - "static const ::google::protobuf::internal::MigrationSchema schemas[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); - { - int offset = 0; - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateSchema(printer, offset, - pairs[i].second); - offset += pairs[i].first; - } - } - printer->Outdent(); - printer->Print( - "};\n" - "\nstatic " - "::google::protobuf::Message const * const file_default_instances[] = {\n"); - printer->Indent(); - for (int i = 0; i < message_generators_.size(); i++) { - const Descriptor* descriptor = message_generators_[i]->descriptor_; - printer->Print( - "reinterpret_cast<const " - "::google::protobuf::Message*>(&_$classname$_default_instance_),\n", - "classname", ClassName(descriptor, false)); - } - printer->Outdent(); - printer->Print( - "};\n" - "\n"); - } else { - // we still need these symbols to exist - printer->Print( - // MSVC doesn't like empty arrays, so we add a dummy. - "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n" - "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" - "static const ::google::protobuf::Message* const* " - "file_default_instances = NULL;\n"); - } - // --------------------------------------------------------------- + // --------------------------------------------------------------- - // protobuf_AssignDescriptorsOnce(): The first time it is called, calls - // AssignDescriptors(). All later times, waits for the first call to - // complete and then returns. - string message_factory = "NULL"; + // protobuf_AssignDescriptorsOnce(): The first time it is called, calls + // AssignDescriptors(). All later times, waits for the first call to + // complete and then returns. + string message_factory = "NULL"; printer->Print( - "namespace {\n" - "\n" "void protobuf_AssignDescriptors() {\n" // Make sure the file has found its way into the pool. If a descriptor // is requested *during* static init then AddDescriptors() may not have @@ -733,20 +697,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { ? "file_level_service_descriptors" : "NULL", "factory", message_factory); - // TODO(gerbens) have the compiler include the schemas for map types - // so that this can go away, and we can potentially use table driven - // serialization for map types as well. - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) continue; - printer->Print( - "file_level_metadata[$index$].reflection = " - "$parent$::$classname$::CreateReflection(file_level_metadata[$index$]" - ".descriptor, _$classname$_default_instance_._instance.get_mutable());\n", - "index", SimpleItoa(i), "parent", - ClassName(message_generators_[i]->descriptor_->containing_type(), - false), - "classname", ClassName(message_generators_[i]->descriptor_, false)); - } printer->Print( "}\n" "\n" @@ -769,7 +719,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // protobuf_AssignDescriptorsOnce, because that is called from all the // GetMetadata member methods. printer->Print( - "void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;\n" + "void protobuf_RegisterTypes(const ::std::string&) " + "GOOGLE_PROTOBUF_ATTRIBUTE_COLD;\n" "void protobuf_RegisterTypes(const ::std::string&) {\n" " protobuf_AssignDescriptorsOnce();\n"); printer->Indent(); @@ -783,63 +734,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Outdent(); printer->Print( - "}\n" - "\n" - "} // namespace\n"); - } - - // Now generate the InitDefaultsImpl() function. - printer->Print( - "void TableStruct::InitDefaultsImpl() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" - // Force initialization of primitive values we depend on. - " ::google::protobuf::internal::InitProtobufDefaults();\n"); - - printer->Indent(); - - // Call the InitDefaults() methods for all of our dependencies, to make - // sure they get added first. - for (int i = 0; i < file_->dependency_count(); i++) { - const FileDescriptor* dependency = file_->dependency(i); - // Print the namespace prefix for the dependency. - string file_namespace = QualifiedFileLevelSymbol( - dependency->package(), FileLevelNamespace(dependency->name())); - // Call its AddDescriptors function. - printer->Print("$file_namespace$::InitDefaults();\n", "file_namespace", - file_namespace); - } - - // Allocate and initialize default instances. This can't be done lazily - // since default instances are returned by simple accessors and are used with - // extensions. Speaking of which, we also register extensions at this time. - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateDefaultInstanceAllocator(printer); - } - for (int i = 0; i < extension_generators_.size(); i++) { - extension_generators_[i]->GenerateRegistration(printer); - } - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateDefaultInstanceInitializer(printer); - } - printer->Outdent(); - printer->Print( - "}\n" - "\n" - "void InitDefaults() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl);\n" - "}\n"); - - // ----------------------------------------------------------------- + "}\n" + "\n"); - // Now generate the AddDescriptors() function. - printer->Print( - "namespace {\n" - "void AddDescriptorsImpl() {\n" - " InitDefaults();\n"); + // Now generate the AddDescriptors() function. + printer->Print( + "void AddDescriptorsImpl() {\n" + " InitDefaults();\n"); + printer->Indent(); - printer->Indent(); - if (HasDescriptorMethods(file_, options_)) { // Embed the descriptor. We simply serialize the entire // FileDescriptorProto // and embed it as a string literal, which is parsed and built into real @@ -850,10 +753,11 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { file_proto.SerializeToString(&file_data); printer->Print("static const char descriptor[] " - "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) " + "= {\n"); printer->Indent(); - if (file_data.size() > 66535) { + if (file_data.size() > 65535) { // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 // bytes in length". Declare a static array of characters rather than use // a string literal. Only write 25 bytes per line. @@ -887,31 +791,27 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" " \"$filename$\", &protobuf_RegisterTypes);\n", "filename", file_->name()); - } // Call the AddDescriptors() methods for all of our dependencies, to make // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. - string file_namespace = QualifiedFileLevelSymbol( - dependency->package(), FileLevelNamespace(dependency->name())); + string file_namespace = FileLevelNamespace(dependency); // Call its AddDescriptors function. - printer->Print("$file_namespace$::AddDescriptors();\n", "file_namespace", + printer->Print("::$file_namespace$::AddDescriptors();\n", "file_namespace", file_namespace); } printer->Outdent(); printer->Print( "}\n" - "} // anonymous namespace\n" "\n" "void AddDescriptors() {\n" " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" " ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n" "}\n"); - if (StaticInitializersForced(file_, options_)) { printer->Print( "// Force AddDescriptors() to be called at dynamic initialization " "time.\n" @@ -920,24 +820,213 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { " AddDescriptors();\n" " }\n" "} static_descriptor_initializer;\n"); - } } -void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { - if (package_parts_.size() > 0) printer->Print("\n"); +void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { + const string scc_name = ClassName(scc->GetRepresentative()); + printer->Print( + "void InitDefaults$scc_name$Impl() {\n" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" + // Force initialization of primitive values we depend on. + " ::google::protobuf::internal::InitProtobufDefaults();\n", + "scc_name", scc_name); - for (int i = 0; i < package_parts_.size(); i++) { - printer->Print("namespace $part$ {\n", - "part", package_parts_[i]); + printer->Indent(); + + // Call the InitDefaults() methods for all of our dependencies, to make + // sure they get added first. + for (int i = 0; i < scc->children.size(); i++) { + const SCC* child_scc = scc->children[i]; + const FileDescriptor* dependency = child_scc->GetRepresentative()->file(); + // Print the namespace prefix for the dependency. + string file_namespace = FileLevelNamespace(dependency); + std::map<string, string> variables; + variables["file_namespace"] = file_namespace; + variables["scc_name"] = ClassName(child_scc->GetRepresentative(), false); + bool using_weak_fields = UsingImplicitWeakFields(file_, options_); + if (using_weak_fields) { + // We're building for lite with implicit weak fields, so we need to handle + // the possibility that this InitDefaults function is not linked into the + // binary. Some of these might actually be guaranteed to be non-null since + // we might have a strong reference to the dependency (via a required + // field, for example), but it's simplest to just assume that any of them + // could be null. + printer->Print( + variables, + "if (&$file_namespace$::InitDefaults$scc_name$ != NULL) {\n" + " $file_namespace$::InitDefaults$scc_name$();\n" + "}\n"); + } else { + printer->Print(variables, + "$file_namespace$::InitDefaults$scc_name$();\n"); + } + } + + // First construct all the necessary default instances. + for (int i = 0; i < message_generators_.size(); i++) { + if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { + continue; + } + // TODO(gerbens) This requires this function to be friend. Remove + // the need for this. + message_generators_[i]->GenerateFieldDefaultInstances(printer); + printer->Print( + "{\n" + " void* ptr = &$ns$::_$classname$_default_instance_;\n" + " new (ptr) $ns$::$classname$();\n", + "ns", Namespace(message_generators_[i]->descriptor_), + "classname", ClassName(message_generators_[i]->descriptor_)); + if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) { + printer->Print( + " ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);\n"); + } + printer->Print("}\n"); } + + // TODO(gerbens) make default instances be the same as normal instances. + // Default instances differ from normal instances because they have cross + // linked message fields. + for (int i = 0; i < message_generators_.size(); i++) { + if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { + continue; + } + printer->Print("$classname$::InitAsDefaultInstance();\n", "classname", + QualifiedClassName(message_generators_[i]->descriptor_)); + } + printer->Outdent(); + printer->Print("}\n\n"); + printer->Print( + "void InitDefaults$scc_name$() {\n" + " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" + " ::google::protobuf::GoogleOnceInit(&once, " + "&InitDefaults$scc_name$Impl);\n" + "}\n\n", + "scc_name", scc_name); } -void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { - if (package_parts_.size() > 0) printer->Print("\n"); +void FileGenerator::GenerateInitializationCode(io::Printer* printer) { + // Messages depend on the existence of a default instance, which has to + // initialized properly. The default instances are allocated in the data + // segment, but we can't quite allocate the type directly. The destructors + // cannot run at program exit as this could lead to segfaults in a threaded + // environment. Hence these instances must be inplace constructed at first + // use. + + if (options_.table_driven_parsing) { + // TODO(ckennelly): Gate this with the same options flag to enable + // table-driven parsing. + printer->Print( + "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n" + " const TableStruct::entries[] " + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + printer->Indent(); - for (int i = package_parts_.size() - 1; i >= 0; i--) { - printer->Print("} // namespace $part$\n", - "part", package_parts_[i]); + std::vector<size_t> entries; + size_t count = 0; + for (int i = 0; i < message_generators_.size(); i++) { + size_t value = message_generators_[i]->GenerateParseOffsets(printer); + entries.push_back(value); + count += value; + } + + // We need these arrays to exist, and MSVC does not like empty arrays. + if (count == 0) { + printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n"); + } + + printer->Outdent(); + printer->Print( + "};\n" + "\n" + "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n" + " const TableStruct::aux[] " + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + printer->Indent(); + + std::vector<size_t> aux_entries; + count = 0; + for (int i = 0; i < message_generators_.size(); i++) { + size_t value = message_generators_[i]->GenerateParseAuxTable(printer); + aux_entries.push_back(value); + count += value; + } + + if (count == 0) { + printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); + } + + printer->Outdent(); + printer->Print( + "};\n" + "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n" + " TableStruct::schema[] " + "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + printer->Indent(); + + size_t offset = 0; + size_t aux_offset = 0; + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); + offset += entries[i]; + aux_offset += aux_entries[i]; + } + + if (message_generators_.empty()) { + printer->Print("{ NULL, NULL, 0, -1, -1, false },\n"); + } + + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + } + + if (!message_generators_.empty() && options_.table_driven_serialization) { + printer->Print( + "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] " + "= {\n"); + printer->Indent(); + std::vector<int> field_metadata_offsets; + int idx = 0; + for (int i = 0; i < message_generators_.size(); i++) { + field_metadata_offsets.push_back(idx); + idx += message_generators_[i]->GenerateFieldMetadata(printer); + } + field_metadata_offsets.push_back(idx); + printer->Outdent(); + printer->Print( + "};\n" + "const ::google::protobuf::internal::SerializationTable " + "TableStruct::serialization_table[] = {\n"); + printer->Indent(); + // We rely on the order we layout the tables to match the order we + // calculate them with FlattenMessagesInFile, so we check here that + // these match exactly. + std::vector<const Descriptor*> calculated_order = + FlattenMessagesInFile(file_); + GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); + for (int i = 0; i < message_generators_.size(); i++) { + GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); + printer->Print( + "{$num_fields$, TableStruct::field_metadata + $index$},\n", + "classname", message_generators_[i]->classname_, "num_fields", + SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]), + "index", SimpleItoa(field_metadata_offsets[i])); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + } + + // ----------------------------------------------------------------- + // All functionality that need private access. + + // Now generate the InitDefaults for each SCC. + for (int i = 0; i < message_generators_.size(); i++) { + if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { + GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), printer); + } } } @@ -985,6 +1074,9 @@ void FileGenerator::GenerateBottomHeaderGuard( } void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { + if (UsingImplicitWeakFields(file_, options_)) { + printer->Print("#include <google/protobuf/implicit_weak_message.h>\n"); + } printer->Print( "#include <google/protobuf/stubs/common.h>\n" @@ -1114,31 +1206,56 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { void FileGenerator::GenerateGlobalStateFunctionDeclarations( io::Printer* printer) { - // Forward-declare the AddDescriptors, AssignDescriptors - // functions, so that we can declare them to be friends of each class. +// Forward-declare the AddDescriptors, InitDefaults because these are called +// by .pb.cc files depending on this file. printer->Print( "\n" "namespace $file_namespace$ {\n" - "// Internal implementation detail -- do not call these.\n" + "// Internal implementation detail -- do not use these members.\n" "struct $dllexport_decl$TableStruct {\n" + // These tables describe how to serialize and parse messages. Used + // for table driven code. " static const ::google::protobuf::internal::ParseTableField entries[];\n" " static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n" - " static const ::google::protobuf::internal::ParseTable schema[];\n" - " static const ::google::protobuf::uint32 offsets[];\n" + " static const ::google::protobuf::internal::ParseTable schema[$num$];\n" " static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n" " static const ::google::protobuf::internal::SerializationTable " "serialization_table[];\n" - // The following function(s) need to be able to access private members of - // the messages defined in the file. So we make them static members. - // This is the internal implementation of InitDefaults. It should only - // be called by InitDefaults which makes sure it will be called only once. - " static void InitDefaultsImpl();\n" - "};\n" - "void $dllexport_decl$AddDescriptors();\n" - "void $dllexport_decl$InitDefaults();\n" - "} // namespace $file_namespace$\n", - "file_namespace", FileLevelNamespace(file_->name()), "dllexport_decl", + " static const ::google::protobuf::uint32 offsets[];\n" + "};\n", + "file_namespace", FileLevelNamespace(file_), "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ", + "num", SimpleItoa(std::max(size_t(1), message_generators_.size()))); + if (HasDescriptorMethods(file_, options_)) { + printer->Print( + "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + } + for (int i = 0; i < message_generators_.size(); i++) { + if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; + string scc_name = ClassName(message_generators_[i]->descriptor_); + // TODO(gerbens) Remove the Impl from header. This is solely because + // it currently still needs to be a friend of the protos. + printer->Print( + "void $dllexport_decl$InitDefaults$scc_name$Impl();\n" + "void $dllexport_decl$InitDefaults$scc_name$();\n", + "scc_name", scc_name, "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + } + // TODO(gerbens) This is for proto1 interoperability. Remove when proto1 + // is gone. + printer->Print( + "inline void $dllexport_decl$InitDefaults() {\n", "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + for (int i = 0; i < message_generators_.size(); i++) { + if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; + string scc_name = ClassName(message_generators_[i]->descriptor_); + printer->Print(" InitDefaults$scc_name$();\n", "scc_name", scc_name); + } + printer->Print("}\n"); + printer->Print( + "} // namespace $file_namespace$\n", + "file_namespace", FileLevelNamespace(file_)); } void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { @@ -1187,41 +1304,6 @@ void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { } void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { - // An aside about inline functions in .proto.h mode: - // - // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally - // moving much of the inline functions to the .pb.cc file, which can be a - // significant performance benefit for compilation time, at the expense - // of non-inline function calls. - // - // However, in .proto.h mode, the definition of the internal dependent - // base class must remain in the header, and can never be out-lined. The - // dependent base class also needs access to has-bit manipuation - // functions, so the has-bit functions must be unconditionally inlined in - // proto_h mode. - // - // This gives us three flavors of functions: - // - // 1. Functions on the message not used by the internal dependent base - // class: in .proto.h mode, only some functions are defined on the - // message class; others are defined on the dependent base class. - // These are guarded and can be out-lined. These are generated by - // GenerateInlineMethods, and include has_* bit functions in - // non-proto_h mode. - // - // 2. Functions on the internal dependent base class: these functions - // are dependent on a template parameter, so they always need to - // remain in the header. - // - // 3. Functions on the message that are used by the dependent base: the - // dependent base class down casts itself to the message - // implementation class to access these functions (the has_* bit - // manipulation functions). Unlike #1, these functions must - // unconditionally remain in the header. These are emitted by - // GenerateDependentInlineMethods, even though they are not actually - // dependent. - - printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); // TODO(gerbens) remove pragmas when gcc is no longer used. Current version // of gcc fires a bogus error when compiled with strict-aliasing. printer->Print( @@ -1242,7 +1324,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { "#ifdef __GNUC__\n" " #pragma GCC diagnostic pop\n" "#endif // __GNUC__\n"); - printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index e10fe2f3..7e61cbad 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -35,10 +35,12 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ +#include <algorithm> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <set> #include <string> #include <vector> #include <google/protobuf/stubs/common.h> @@ -82,16 +84,21 @@ class FileGenerator { const string& info_path); void GenerateSource(io::Printer* printer); + int NumMessages() const { return message_generators_.size(); } + // Similar to GenerateSource but generates only one message + void GenerateSourceForMessage(int idx, io::Printer* printer); + void GenerateGlobalSource(io::Printer* printer); + private: // Internal type used by GenerateForwardDeclarations (defined in file.cc). class ForwardDeclarations; - // Generate the BuildDescriptors() procedure, which builds all descriptors - // for types defined in the file. - void GenerateBuildDescriptors(io::Printer* printer); + void GenerateSourceIncludes(io::Printer* printer); + void GenerateSourceDefaultInstance(int idx, io::Printer* printer); - void GenerateNamespaceOpeners(io::Printer* printer); - void GenerateNamespaceClosers(io::Printer* printer); + void GenerateInitForSCC(const SCC* scc, io::Printer* printer); + void GenerateInitializationCode(io::Printer* printer); + void GenerateReflectionInitializationCode(io::Printer* printer); // For other imports, generates their forward-declarations. void GenerateForwardDeclarations(io::Printer* printer); @@ -143,11 +150,23 @@ class FileGenerator { // a breaking change so we prefer the #undef approach. void GenerateMacroUndefs(io::Printer* printer); + bool IsSCCRepresentative(const Descriptor* d) { + return GetSCCRepresentative(d) == d; + } + const Descriptor* GetSCCRepresentative(const Descriptor* d) { + return GetSCC(d)->GetRepresentative(); + } + const SCC* GetSCC(const Descriptor* d) { + return scc_analyzer_.GetSCC(d); + } + + const FileDescriptor* file_; const Options options_; SCCAnalyzer scc_analyzer_; + // Contains the post-order walk of all the messages (and child messages) in // this file. If you need a pre-order walk just reverse iterate. std::vector<MessageGenerator*> message_generators_; @@ -155,10 +174,8 @@ class FileGenerator { std::vector<ServiceGenerator*> service_generators_; std::vector<ExtensionGenerator*> extension_generators_; - // These members are just for owning (and thus proper deleting). Some of the - // message_ and enum_generators above are owned by child messages. - google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > - message_generators_owner_; + // These members are just for owning (and thus proper deleting). + // Nested (enum/extension)_generators are owned by child messages. google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_owner_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > service_generators_owner_; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 68abd0ef..e01e5dca 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -46,6 +46,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> namespace google { namespace protobuf { @@ -84,7 +85,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, // __declspec(dllimport) depending on what is being compiled. // Options file_options; - + bool split_source = false; for (int i = 0; i < options.size(); i++) { if (options[i].first == "dllexport_decl") { file_options.dllexport_decl = options[i].second; @@ -98,10 +99,14 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.annotation_guard_name = options[i].second; } else if (options[i].first == "lite") { file_options.enforce_lite = true; + } else if (options[i].first == "lite_implicit_weak_fields") { + file_options.lite_implicit_weak_fields = true; } else if (options[i].first == "table_driven_parsing") { file_options.table_driven_parsing = true; } else if (options[i].first == "table_driven_serialization") { file_options.table_driven_serialization = true; + } else if (options[i].first == "split_source") { + split_source = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -135,14 +140,13 @@ bool CppGenerator::Generate(const FileDescriptor* file, } } - basename.append(".pb"); { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".h")); + generator_context->Open(basename + ".pb.h")); GeneratedCodeInfo annotations; io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( &annotations); - string info_path = basename + ".h.meta"; + string info_path = basename + ".pb.h.meta"; io::Printer printer(output.get(), '$', file_options.annotate_headers ? &annotation_collector : NULL); @@ -156,9 +160,24 @@ bool CppGenerator::Generate(const FileDescriptor* file, } // Generate cc file. - { + if (split_source) { + { + // This is the global .cc file, containing enum/services/tables/reflection + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".pb.cc")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateGlobalSource(&printer); + } + for (int i = 0; i < file_generator.NumMessages(); i++) { + // TODO(gerbens) Agree on naming scheme. + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + "." + SimpleItoa(i) + ".cc")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSourceForMessage(i, &printer); + } + } else { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".cc")); + generator_context->Open(basename + ".pb.cc")); io::Printer printer(output.get(), '$'); file_generator.GenerateSource(&printer); } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 00959796..4aa77d06 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -32,10 +32,11 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/stubs/hash.h> #include <limits> #include <map> +#include <queue> #include <vector> -#include <google/protobuf/stubs/hash.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> @@ -105,6 +106,30 @@ bool HasExtension(const Descriptor* descriptor) { return false; } +// Encode [0..63] as 'A'-'Z', 'a'-'z', '0'-'9', '_' +char Base63Char(int value) { + GOOGLE_CHECK_GE(value, 0); + if (value < 26) return 'A' + value; + value -= 26; + if (value < 26) return 'a' + value; + value -= 26; + if (value < 10) return '0' + value; + GOOGLE_CHECK_EQ(value, 10); + return '_'; +} + +// Given a c identifier has 63 legal characters we can't implement base64 +// encoding. So we return the k least significant "digits" in base 63. +template <typename I> +string Base63(I n, int k) { + string res; + while (k-- > 0) { + res += Base63Char(static_cast<int>(n % 63)); + n /= 63; + } + return res; +} + } // namespace string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { @@ -137,44 +162,63 @@ const char kThickSeparator[] = const char kThinSeparator[] = "// -------------------------------------------------------------------\n"; -string ClassName(const Descriptor* descriptor, bool qualified) { - - // Find "outer", the descriptor of the top-level message in which - // "descriptor" is embedded. - const Descriptor* outer = descriptor; - while (outer->containing_type() != NULL) outer = outer->containing_type(); - - const string& outer_name = outer->full_name(); - string inner_name = descriptor->full_name().substr(outer_name.size()); - - if (qualified) { - return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name); - } else { - return outer->name() + DotsToUnderscores(inner_name); +bool CanInitializeByZeroing(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() == 0; + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() == 0; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() == 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() == 0; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() == 0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() == 0; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() == 0; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() == false; + default: + return false; } } -string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { +string ClassName(const Descriptor* descriptor) { + const Descriptor* parent = descriptor->containing_type(); + string res; + if (parent) res += ClassName(parent) + "_"; + res += descriptor->name(); + if (IsMapEntryMessage(descriptor)) res += "_DoNotUse"; + return res; +} + +string ClassName(const EnumDescriptor* enum_descriptor) { if (enum_descriptor->containing_type() == NULL) { - if (qualified) { - return "::" + DotsToColons(enum_descriptor->full_name()); - } else { - return enum_descriptor->name(); - } + return enum_descriptor->name(); } else { - string result = ClassName(enum_descriptor->containing_type(), qualified); - result += '_'; - result += enum_descriptor->name(); - return result; + return ClassName(enum_descriptor->containing_type()) + "_" + + enum_descriptor->name(); } } +string Namespace(const string& package) { + if (package.empty()) return ""; + return "::" + DotsToColons(package); +} + string DefaultInstanceName(const Descriptor* descriptor) { string prefix = descriptor->file()->package().empty() ? "" : "::"; return prefix + DotsToColons(descriptor->file()->package()) + "::_" + ClassName(descriptor, false) + "_default_instance_"; } +string ReferenceFunctionName(const Descriptor* descriptor) { + return QualifiedClassName(descriptor) + "_Reference"; +} + string DependentBaseClassTemplateName(const Descriptor* descriptor) { return ClassName(descriptor, false) + "_InternalBase"; } @@ -210,6 +254,30 @@ string EnumValueName(const EnumValueDescriptor* enum_value) { return result; } +int EstimateAlignmentSize(const FieldDescriptor* field) { + if (field == NULL) return 0; + if (field->is_repeated()) return 8; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: + return 1; + + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + return 4; + + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_MESSAGE: + return 8; + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; // Make compiler happy. +} + string FieldConstantName(const FieldDescriptor *field) { string field_name = UnderscoresToCamelCase(field->name(), true); string result = "k" + field_name + "FieldNumber"; @@ -484,19 +552,6 @@ string SafeFunctionName(const Descriptor* descriptor, return function_name; } -bool StaticInitializersForced(const FileDescriptor* file, - const Options& options) { - if (HasDescriptorMethods(file, options) || file->extension_count() > 0) { - return true; - } - for (int i = 0; i < file->message_type_count(); ++i) { - if (HasExtension(file->message_type(i))) { - return true; - } - } - return false; -} - static bool HasMapFields(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); ++i) { @@ -672,13 +727,11 @@ void Flatten(const Descriptor* descriptor, } // namespace -std::vector<const Descriptor*> FlattenMessagesInFile( - const FileDescriptor* file) { - std::vector<const Descriptor*> result; +void FlattenMessagesInFile(const FileDescriptor* file, + std::vector<const Descriptor*>* result) { for (int i = 0; i < file->message_type_count(); i++) { - Flatten(file->message_type(i), &result); + Flatten(file->message_type(i), result); } - return result; } bool HasWeakFields(const Descriptor* descriptor) { @@ -689,6 +742,27 @@ bool HasWeakFields(const FileDescriptor* file) { return false; } +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options) { + return options.lite_implicit_weak_fields && + GetOptimizeFor(file, options) == FileOptions::LITE_RUNTIME; +} + + +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options) { + return UsingImplicitWeakFields(field->file(), options) && + field->type() == FieldDescriptor::TYPE_MESSAGE && + !field->is_required() && !field->is_repeated() && !field->is_map() && + field->containing_oneof() == NULL && + field->message_type()->file() != field->file(); +} + +struct CompareDescriptors { + bool operator()(const Descriptor* a, const Descriptor* b) { + return a->full_name() < b->full_name(); + } +}; + SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) { // Must not have visited already. GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0); @@ -728,10 +802,33 @@ SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) { if (scc_desc == descriptor) break; } + + // The order of descriptors is random and depends how this SCC was + // discovered. In-order to ensure maximum stability we sort it by name. + std::sort(scc->descriptors.begin(), scc->descriptors.end(), + CompareDescriptors()); + AddChildren(scc); } return result; } +void SCCAnalyzer::AddChildren(SCC* scc) { + std::set<const SCC*> seen; + for (int i = 0; i < scc->descriptors.size(); i++) { + const Descriptor* descriptor = scc->descriptors[i]; + for (int j = 0; j < descriptor->field_count(); j++) { + const Descriptor* child_msg = descriptor->field(j)->message_type(); + if (child_msg) { + const SCC* child = GetSCC(child_msg); + if (child == scc) continue; + if (seen.insert(child).second) { + scc->children.push_back(child); + } + } + } + } +} + MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) { if (analysis_cache_.count(scc)) return analysis_cache_[scc]; MessageAnalysis result = MessageAnalysis(); @@ -784,6 +881,46 @@ MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) { return analysis_cache_[scc] = result; } +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields) { + // Collect sub messages + for (int i = 0; i < d->nested_type_count(); i++) { + ListAllFields(d->nested_type(i), fields); + } + // Collect message level extensions. + for (int i = 0; i < d->extension_count(); i++) { + fields->push_back(d->extension(i)); + } + // Add types of fields necessary + for (int i = 0; i < d->field_count(); i++) { + fields->push_back(d->field(i)); + } +} + +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields) { + // Collect file level message. + for (int i = 0; i < d->message_type_count(); i++) { + ListAllFields(d->message_type(i), fields); + } + // Collect message level extensions. + for (int i = 0; i < d->extension_count(); i++) { + fields->push_back(d->extension(i)); + } +} + +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types) { + for (int i = 0; i < fd->service_count(); i++) { + const ServiceDescriptor* sd = fd->service(i); + for (int j = 0; j < sd->method_count(); j++) { + const MethodDescriptor* method = sd->method(j); + types->push_back(method->input_type()); + types->push_back(method->output_type()); + } + } +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 6ae68591..550438dd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -38,16 +38,13 @@ #include <map> #include <string> #include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/strutil.h> namespace google { namespace protobuf { - -namespace io { -class Printer; -} - namespace compiler { namespace cpp { @@ -56,6 +53,31 @@ namespace cpp { extern const char kThickSeparator[]; extern const char kThinSeparator[]; +// Name space of the proto file. This namespace is such that the string +// "<namespace>::some_name" is the correct fully qualified namespace. +// This means if the package is empty the namespace is "", and otherwise +// the namespace is "::foo::bar::...::baz" without trailing semi-colons. +string Namespace(const string& package); +inline string Namespace(const FileDescriptor* d) { + return Namespace(d->package()); +} +template <typename Desc> +string Namespace(const Desc* d) { + return Namespace(d->file()); +} + +// Returns true if it's safe to reset "field" to zero. +bool CanInitializeByZeroing(const FieldDescriptor* field); + +string ClassName(const Descriptor* descriptor); +string ClassName(const EnumDescriptor* enum_descriptor); +template <typename Desc> +string QualifiedClassName(const Desc* d) { + return Namespace(d) + "::" + ClassName(d); +} + +// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very +// unreadable at the callsite. // Returns the non-nested type name for the given type. If "qualified" is // true, prefix the type with the full namespace. For example, if you had: // package foo.bar; @@ -64,12 +86,22 @@ extern const char kThinSeparator[]; // ::foo::bar::Baz_Qux // While the non-qualified version would be: // Baz_Qux -string ClassName(const Descriptor* descriptor, bool qualified); -string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +inline string ClassName(const Descriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor); +} + +inline string ClassName(const EnumDescriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor) : ClassName(descriptor); +} // Fully qualified name of the default_instance of this message. string DefaultInstanceName(const Descriptor* descriptor); +// Returns the name of a no-op function that we can call to introduce a linker +// dependency on the given message type. This is used to implement implicit weak +// fields. +string ReferenceFunctionName(const Descriptor* descriptor); + // Name of the CRTP class template (for use with proto_h). // This is a class name, like "ProtoName_InternalBase". string DependentBaseClassTemplateName(const Descriptor* descriptor); @@ -92,6 +124,12 @@ string FieldName(const FieldDescriptor* field); // Get the sanitized name that should be used for the given enum in C++ code. string EnumValueName(const EnumValueDescriptor* enum_value); +// Returns an estimate of the compiler's alignment for the field. This +// can't guarantee to be correct because the generated code could be compiled on +// different systems with different alignment rules. The estimates below assume +// 64-bit pointers. +int EstimateAlignmentSize(const FieldDescriptor* field); + // Get the unqualified name that should be used for a field's field // number constant. string FieldConstantName(const FieldDescriptor *field); @@ -150,6 +188,12 @@ string FilenameIdentifier(const string& filename); // For each .proto file generates a unique namespace. In this namespace global // definitions are put to prevent collisions. string FileLevelNamespace(const string& filename); +inline string FileLevelNamespace(const FileDescriptor* file) { + return FileLevelNamespace(file->name()); +} +inline string FileLevelNamespace(const Descriptor* d) { + return FileLevelNamespace(d->file()); +} // Return the qualified C++ name for a file level symbol. string QualifiedFileLevelSymbol(const string& package, const string& name); @@ -225,10 +269,6 @@ inline bool HasFastArraySerialization(const FileDescriptor* file, return GetOptimizeFor(file, options) == FileOptions::SPEED; } -// Returns whether we have to generate code with static initializers. -bool StaticInitializersForced(const FileDescriptor* file, - const Options& options); - inline bool IsMapEntryMessage(const Descriptor* descriptor) { return descriptor->options().map_entry(); @@ -289,12 +329,25 @@ inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( } // This orders the messages in a .pb.cc as it's outputted by file.cc -std::vector<const Descriptor*> FlattenMessagesInFile( - const FileDescriptor* file); +void FlattenMessagesInFile(const FileDescriptor* file, + std::vector<const Descriptor*>* result); +inline std::vector<const Descriptor*> FlattenMessagesInFile( + const FileDescriptor* file) { + std::vector<const Descriptor*> result; + FlattenMessagesInFile(file, &result); + return result; +} bool HasWeakFields(const Descriptor* desc); bool HasWeakFields(const FileDescriptor* desc); +// Indicates whether we should use implicit weak fields for this file. +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options); + +// Indicates whether to treat this field as implicitly weak. +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options); + // Returns true if the "required" restriction check should be ignored for the // given field. inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, @@ -302,8 +355,46 @@ inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, return false; } +class LIBPROTOC_EXPORT NamespaceOpener { + public: + explicit NamespaceOpener(io::Printer* printer) : printer_(printer) {} + NamespaceOpener(const string& name, io::Printer* printer) + : printer_(printer) { + ChangeTo(name); + } + ~NamespaceOpener() { ChangeTo(""); } + + void ChangeTo(const string& name) { + std::vector<string> new_stack_ = + Split(name, "::", true); + int len = std::min(name_stack_.size(), new_stack_.size()); + int common_idx = 0; + while (common_idx < len) { + if (name_stack_[common_idx] != new_stack_[common_idx]) break; + common_idx++; + } + for (int i = name_stack_.size() - 1; i >= common_idx; i--) { + printer_->Print("} // namespace $ns$\n", "ns", name_stack_[i]); + } + name_stack_.swap(new_stack_); + for (int i = common_idx; i < name_stack_.size(); i++) { + printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]); + } + } + + private: + io::Printer* printer_; + std::vector<string> name_stack_; +}; + +// Description of each strongly connected component. Note that the order +// of both the descriptors in this SCC and the order of children is +// deterministic. struct SCC { std::vector<const Descriptor*> descriptors; + std::vector<const SCC*> children; + + const Descriptor* GetRepresentative() const { return descriptors[0]; } }; struct MessageAnalysis { @@ -357,8 +448,16 @@ class LIBPROTOC_EXPORT SCCAnalyzer { // Tarjan's Strongly Connected Components algo NodeData DFS(const Descriptor* descriptor); + + // Add the SCC's that are children of this SCC to its children. + void AddChildren(SCC* scc); }; +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields); +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index da33d29b..d06a1d39 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -114,50 +114,13 @@ MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - variables_, - "public:\n" - "class $map_classname$ : public " - "::google::protobuf::internal::MapEntry<$map_classname$, \n" - " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" - " $default_enum_value$ > {\n" - "public:\n" - " typedef ::google::protobuf::internal::MapEntry<$map_classname$, \n" - " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" - " $default_enum_value$ > SuperType;\n" - " $map_classname$();\n" - " $map_classname$(::google::protobuf::Arena* arena);\n" - " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n" - " void MergeFrom(const $map_classname$& other);\n" - " static const Message* internal_default_instance() { return " - "reinterpret_cast<const " - "Message*>(&_$map_classname$_default_instance_); }\n" - " ::google::protobuf::Metadata GetMetadata() const;\n" - "};\n"); - } else { - printer->Print(variables_, - "public:\n" - "typedef ::google::protobuf::internal::MapEntryLite<\n" - " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" - " $default_enum_value$ >\n" - " $map_classname$;\n"); - } printer->Print(variables_, - "private:\n" "::google::protobuf::internal::MapField$lite$<\n" " $map_classname$,\n" " $key_cpp$, $val_cpp$,\n" " $key_wire_type$,\n" " $val_wire_type$,\n" - " $default_enum_value$ > $name$_;\n" - "private:\n"); + " $default_enum_value$ > $name$_;\n"); } void MapFieldGenerator:: @@ -262,7 +225,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, " unknown_fields_stream.WriteVarint32($tag$u);\n" " unknown_fields_stream.WriteVarint32(\n" - " static_cast<google::protobuf::uint32>(data.size()));\n" + " static_cast< ::google::protobuf::uint32>(data.size()));\n" " unknown_fields_stream.WriteString(data);\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 63ebb3c5..cf9c1233 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -48,6 +48,7 @@ #include <google/protobuf/compiler/cpp/cpp_extension.h> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> @@ -109,106 +110,6 @@ struct ExtensionRangeSorter { } }; -// This returns an estimate of the compiler's alignment for the field. This -// can't guarantee to be correct because the generated code could be compiled on -// different systems with different alignment rules. The estimates below assume -// 64-bit pointers. -int EstimateAlignmentSize(const FieldDescriptor* field) { - if (field == NULL) return 0; - if (field->is_repeated()) return 8; - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_BOOL: - return 1; - - case FieldDescriptor::CPPTYPE_INT32: - case FieldDescriptor::CPPTYPE_UINT32: - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_FLOAT: - return 4; - - case FieldDescriptor::CPPTYPE_INT64: - case FieldDescriptor::CPPTYPE_UINT64: - case FieldDescriptor::CPPTYPE_DOUBLE: - case FieldDescriptor::CPPTYPE_STRING: - case FieldDescriptor::CPPTYPE_MESSAGE: - return 8; - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return -1; // Make compiler happy. -} - -// FieldGroup is just a helper for OptimizePadding below. It holds a vector of -// fields that are grouped together because they have compatible alignment, and -// a preferred location in the final field ordering. -class FieldGroup { - public: - FieldGroup() - : preferred_location_(0) {} - - // A group with a single field. - FieldGroup(float preferred_location, const FieldDescriptor* field) - : preferred_location_(preferred_location), - fields_(1, field) {} - - // Append the fields in 'other' to this group. - void Append(const FieldGroup& other) { - if (other.fields_.empty()) { - return; - } - // Preferred location is the average among all the fields, so we weight by - // the number of fields on each FieldGroup object. - preferred_location_ = - (preferred_location_ * fields_.size() + - (other.preferred_location_ * other.fields_.size())) / - (fields_.size() + other.fields_.size()); - fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end()); - } - - void SetPreferredLocation(float location) { preferred_location_ = location; } - const std::vector<const FieldDescriptor*>& fields() const { return fields_; } - - // FieldGroup objects sort by their preferred location. - bool operator<(const FieldGroup& other) const { - return preferred_location_ < other.preferred_location_; - } - - private: - // "preferred_location_" is an estimate of where this group should go in the - // final list of fields. We compute this by taking the average index of each - // field in this group in the original ordering of fields. This is very - // approximate, but should put this group close to where its member fields - // originally went. - float preferred_location_; - std::vector<const FieldDescriptor*> fields_; - // We rely on the default copy constructor and operator= so this type can be - // used in a vector. -}; - -// Helper for the code that emits the Clear() method. -bool CanInitializeByZeroing(const FieldDescriptor* field) { - if (field->is_repeated() || field->is_extension()) return false; - switch (field->cpp_type()) { - case internal::WireFormatLite::CPPTYPE_ENUM: - return field->default_value_enum()->number() == 0; - case internal::WireFormatLite::CPPTYPE_INT32: - return field->default_value_int32() == 0; - case internal::WireFormatLite::CPPTYPE_INT64: - return field->default_value_int64() == 0; - case internal::WireFormatLite::CPPTYPE_UINT32: - return field->default_value_uint32() == 0; - case internal::WireFormatLite::CPPTYPE_UINT64: - return field->default_value_uint64() == 0; - case internal::WireFormatLite::CPPTYPE_FLOAT: - return field->default_value_float() == 0; - case internal::WireFormatLite::CPPTYPE_DOUBLE: - return field->default_value_double() == 0; - case internal::WireFormatLite::CPPTYPE_BOOL: - return field->default_value_bool() == false; - default: - return false; - } -} - bool IsPOD(const FieldDescriptor* field) { if (field->is_repeated() || field->is_extension()) return false; switch (field->cpp_type()) { @@ -242,133 +143,6 @@ bool CanConstructByZeroing(const FieldDescriptor* field, return ret; } -// Reorder 'fields' so that if the fields are output into a c++ class in the new -// order, fields of similiar family (see below) are together and within each -// family, alignment padding is minimized. -// -// We try to do this while keeping each field as close as possible to its field -// number order so that we don't reduce cache locality much for function that -// access each field in order. Originally, OptimizePadding used declaration -// order for its decisions, but generated code minus the serializer/parsers uses -// the output of OptimizePadding as well (stored in -// MessageGenerator::optimized_order_). Since the serializers use field number -// order, we use that as a tie-breaker. -// -// TODO(ckennelly): If/when we have profiles available for the compiler, use -// those rather than respect declaration order. -// -// We classify each field into a particular "family" of fields, that we perform -// the same operation on in our generated functions. -// -// REPEATED is placed first, as the C++ compiler automatically initializes -// these fields in layout order. -// -// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and -// calls ArenaStringPtr::Destroy on each. -// -// -// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls -// delete on each. We initialize these fields with a NULL pointer (see -// MessageFieldGenerator::GenerateConstructorCode), which allows them to be -// memset. -// -// ZERO_INITIALIZABLE is memset in Clear/SharedCtor -// -// OTHER these fields are initialized one-by-one. -void OptimizePadding(std::vector<const FieldDescriptor*>* fields, - const Options& options) { - // The sorted numeric order of Family determines the declaration order in the - // memory layout. - enum Family { - REPEATED = 0, - STRING = 1, - MESSAGE = 3, - ZERO_INITIALIZABLE = 4, - OTHER = 5, - kMaxFamily - }; - - // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. - std::vector<FieldGroup> aligned_to_1[kMaxFamily]; - std::vector<FieldGroup> aligned_to_4[kMaxFamily]; - std::vector<FieldGroup> aligned_to_8[kMaxFamily]; - for (int i = 0; i < fields->size(); ++i) { - const FieldDescriptor* field = (*fields)[i]; - - Family f = OTHER; - if (field->is_repeated()) { - f = REPEATED; - } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - f = STRING; - } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - f = MESSAGE; - - } else if (CanInitializeByZeroing(field)) { - f = ZERO_INITIALIZABLE; - } - - const int j = field->number(); - switch (EstimateAlignmentSize(field)) { - case 1: aligned_to_1[f].push_back(FieldGroup(j, field)); break; - case 4: aligned_to_4[f].push_back(FieldGroup(j, field)); break; - case 8: aligned_to_8[f].push_back(FieldGroup(j, field)); break; - default: - GOOGLE_LOG(FATAL) << "Unknown alignment size."; - } - } - - // For each family, group fields to optimize padding. - for (int f = 0; f < kMaxFamily; f++) { - // Now group fields aligned to 1 byte into sets of 4, and treat those like a - // single field aligned to 4 bytes. - for (int i = 0; i < aligned_to_1[f].size(); i += 4) { - FieldGroup field_group; - for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) { - field_group.Append(aligned_to_1[f][j]); - } - aligned_to_4[f].push_back(field_group); - } - // Sort by preferred location to keep fields as close to their field number - // order as possible. Using stable_sort ensures that the output is - // consistent across runs. - std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end()); - - // Now group fields aligned to 4 bytes (or the 4-field groups created above) - // into pairs, and treat those like a single field aligned to 8 bytes. - for (int i = 0; i < aligned_to_4[f].size(); i += 2) { - FieldGroup field_group; - for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) { - field_group.Append(aligned_to_4[f][j]); - } - if (i == aligned_to_4[f].size() - 1) { - if (f == OTHER) { - // Move incomplete 4-byte block to the beginning. This is done to - // pair with the (possible) leftover blocks from the - // ZERO_INITIALIZABLE family. - field_group.SetPreferredLocation(-1); - } else { - // Move incomplete 4-byte block to the end. - field_group.SetPreferredLocation(fields->size() + 1); - } - } - aligned_to_8[f].push_back(field_group); - } - // Sort by preferred location. - std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end()); - } - - // Now pull out all the FieldDescriptors in order. - fields->clear(); - for (int f = 0; f < kMaxFamily; ++f) { - for (int i = 0; i < aligned_to_8[f].size(); ++i) { - fields->insert(fields->end(), - aligned_to_8[f][i].fields().begin(), - aligned_to_8[f][i].fields().end()); - } - } -} - - // Emits an if-statement with a condition that evaluates to true if |field| is // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if @@ -423,25 +197,31 @@ bool HasHasMethod(const FieldDescriptor* field) { void CollectMapInfo(const Descriptor* descriptor, std::map<string, string>* variables) { GOOGLE_CHECK(IsMapEntryMessage(descriptor)); + std::map<string, string>& vars = *variables; const FieldDescriptor* key = descriptor->FindFieldByName("key"); const FieldDescriptor* val = descriptor->FindFieldByName("value"); - (*variables)["key"] = PrimitiveTypeName(key->cpp_type()); + vars["key_cpp"] = PrimitiveTypeName(key->cpp_type()); switch (val->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - (*variables)["val"] = FieldMessageTypeName(val); + vars["val_cpp"] = FieldMessageTypeName(val); break; case FieldDescriptor::CPPTYPE_ENUM: - (*variables)["val"] = ClassName(val->enum_type(), true); + vars["val_cpp"] = ClassName(val->enum_type(), true); break; default: - (*variables)["val"] = PrimitiveTypeName(val->cpp_type()); - } - (*variables)["key_wire_type"] = - "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(key->type())); - (*variables)["val_wire_type"] = - "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(val->type())); + vars["val_cpp"] = PrimitiveTypeName(val->cpp_type()); + } + vars["key_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" + + ToUpper(DeclaredTypeMethodName(key->type())); + vars["val_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" + + ToUpper(DeclaredTypeMethodName(val->type())); + if (descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 && + val->type() == FieldDescriptor::TYPE_ENUM) { + const EnumValueDescriptor* default_value = val->default_value_enum(); + vars["default_enum_value"] = Int32ToString(default_value->number()); + } else { + vars["default_enum_value"] = "0"; + } } // Does the given field have a private (internal helper only) has_$name$() @@ -531,21 +311,22 @@ void SetUnknkownFieldsVariable(const Descriptor* descriptor, // =================================================================== MessageGenerator::MessageGenerator(const Descriptor* descriptor, + int index_in_file_messages, const Options& options, SCCAnalyzer* scc_analyzer) : descriptor_(descriptor), + index_in_file_messages_(index_in_file_messages), classname_(ClassName(descriptor, false)), options_(options), field_generators_(descriptor, options), max_has_bit_index_(0), - nested_generators_(new google::protobuf::scoped_ptr< - MessageGenerator>[descriptor->nested_type_count()]), enum_generators_( new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]), extension_generators_(new google::protobuf::scoped_ptr< ExtensionGenerator>[descriptor->extension_count()]), use_dependent_base_(false), num_weak_fields_(0), + message_layout_helper_(new PaddingOptimizer()), scc_analyzer_(scc_analyzer) { // Compute optimized field order to be used for layout and initialization // purposes. @@ -557,7 +338,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, optimized_order_.push_back(field); } } - OptimizePadding(&optimized_order_, options_); + + message_layout_helper_->OptimizeLayout(&optimized_order_, options_); if (HasFieldPresence(descriptor_->file())) { // We use -1 as a sentinel. @@ -573,11 +355,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, } } - for (int i = 0; i < descriptor->nested_type_count(); i++) { - nested_generators_[i].reset(new MessageGenerator(descriptor->nested_type(i), - options, scc_analyzer)); - } - for (int i = 0; i < descriptor->enum_type_count(); i++) { enum_generators_[i].reset( new EnumGenerator(descriptor->enum_type(i), options)); @@ -603,6 +380,9 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, } table_driven_ = TableDrivenParsingEnabled(descriptor_, options_); + + scc_name_ = + ClassName(scc_analyzer_->GetSCC(descriptor_)->GetRepresentative(), false); } MessageGenerator::~MessageGenerator() {} @@ -620,14 +400,6 @@ size_t MessageGenerator::HasBitsSize() const { return sizeof_has_bits; } -void MessageGenerator::Flatten(std::vector<MessageGenerator*>* list) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->Flatten(list); - } - index_in_file_messages_ = list->size(); - list->push_back(this); -} - void MessageGenerator::AddGenerators( std::vector<EnumGenerator*>* enum_generators, std::vector<ExtensionGenerator*>* extension_generators) { @@ -1010,8 +782,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { } // Generate type-specific accessors. - field_generators_.get(field).GenerateInlineAccessorDefinitions(printer, - is_inline); + field_generators_.get(field).GenerateInlineAccessorDefinitions( + printer, /* is_inline = */ true); printer->Print("\n"); } @@ -1056,7 +828,42 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) { void MessageGenerator:: GenerateClassDefinition(io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) return; + if (IsMapEntryMessage(descriptor_)) { + std::map<string, string> vars; + vars["classname"] = classname_; + CollectMapInfo(descriptor_, &vars); + vars["lite"] = + HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite"; + printer->Print( + vars, + "class $classname$ : public " + "::google::protobuf::internal::MapEntry$lite$<$classname$, \n" + " $key_cpp$, $val_cpp$,\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" + " $default_enum_value$ > {\n" + "public:\n" + " typedef ::google::protobuf::internal::MapEntry$lite$<$classname$, \n" + " $key_cpp$, $val_cpp$,\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" + " $default_enum_value$ > SuperType;\n" + " $classname$();\n" + " $classname$(::google::protobuf::Arena* arena);\n" + " void MergeFrom(const $classname$& other);\n" + " static const $classname$* internal_default_instance() { return " + "reinterpret_cast<const " + "$classname$*>(&_$classname$_default_instance_); }\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + printer->Print( + " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n" + " ::google::protobuf::Metadata GetMetadata() const;\n" + "};\n"); + } else { + printer->Print("};\n"); + } + return; + } if (use_dependent_base_) { GenerateDependentBaseClassDefinition(printer); printer->Print("\n"); @@ -1109,26 +916,23 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - // Generate move constructor and move assignment operator for types other than - // Any. - if (!IsAnyMessage(descriptor_)) { - printer->Print(vars, - "#if LANG_CXX11\n" - "$classname$($classname$&& from) noexcept\n" - " : $classname$() {\n" - " *this = ::std::move(from);\n" - "}\n" - "\n" - "inline $classname$& operator=($classname$&& from) noexcept {\n" - " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n" - " if (this != &from) InternalSwap(&from);\n" - " } else {\n" - " CopyFrom(from);\n" - " }\n" - " return *this;\n" - "}\n" - "#endif\n"); - } + // Generate move constructor and move assignment operator. + printer->Print(vars, + "#if LANG_CXX11\n" + "$classname$($classname$&& from) noexcept\n" + " : $classname$() {\n" + " *this = ::std::move(from);\n" + "}\n" + "\n" + "inline $classname$& operator=($classname$&& from) noexcept {\n" + " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n" + " if (this != &from) InternalSwap(&from);\n" + " } else {\n" + " CopyFrom(from);\n" + " }\n" + " return *this;\n" + "}\n" + "#endif\n"); SetUnknkownFieldsVariable(descriptor_, options_, &vars); if (PublicUnknownFieldsAccessors(descriptor_)) { @@ -1199,6 +1003,7 @@ GenerateClassDefinition(io::Printer* printer) { vars["message_index"] = SimpleItoa(index_in_file_messages_); printer->Print( vars, + "static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY\n" "static inline const $classname$* internal_default_instance() {\n" " return reinterpret_cast<const $classname$*>(\n" " &_$classname$_default_instance_);\n" @@ -1358,6 +1163,8 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print("typedef $nested_full_name$ $nested_name$;\n", "nested_name", nested_type->name(), "nested_full_name", ClassName(nested_type, false)); + printer->Annotate("nested_full_name", nested_type); + printer->Annotate("nested_name", nested_type); } } @@ -1548,14 +1355,13 @@ GenerateClassDefinition(io::Printer* printer) { // The TableStruct struct needs access to the private parts, in order to // construct the offsets of all members. - // - // Some InitDefault and Shutdown are defined as static member functions of - // TableStruct such that they are also allowed to access private members. + // TODO(gerbens) Remove the friend for InitDefaults. printer->Print( - "friend struct $file_namespace$::TableStruct;\n", + "friend struct ::$file_namespace$::TableStruct;\n" + "friend void ::$file_namespace$::InitDefaults$scc_name$Impl();\n", // Vars. - "file_namespace", - FileLevelNamespace(descriptor_->file()->name())); + "scc_name", scc_name_, "file_namespace", + FileLevelNamespace(descriptor_)); printer->Outdent(); printer->Print("};"); @@ -1577,7 +1383,7 @@ GenerateDependentInlineMethods(io::Printer* printer) { void MessageGenerator:: GenerateInlineMethods(io::Printer* printer, bool is_inline) { if (IsMapEntryMessage(descriptor_)) return; - GenerateFieldAccessorDefinitions(printer, is_inline); + GenerateFieldAccessorDefinitions(printer, /* is_inline = */ true); // Generate oneof_case() functions. for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { @@ -1634,7 +1440,8 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, std::map<string, string> vars; - vars["classname"] = classname_; + vars["classname"] = ClassName(descriptor_); + vars["classtype"] = QualifiedClassName(descriptor_); vars["offset"] = SimpleItoa(offset); vars["aux_offset"] = SimpleItoa(aux_offset); @@ -1661,48 +1468,34 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, printer->Print(vars, "-1,\n"); } else { printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classname$, _has_bits_),\n"); + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, _has_bits_),\n"); } if (descriptor_->oneof_decl_count() > 0) { printer->Print(vars, "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classname$, _oneof_case_),\n"); + " $classtype$, _oneof_case_),\n"); } else { printer->Print("-1, // no _oneof_case_\n"); } if (descriptor_->extension_range_count() > 0) { printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "_extensions_),\n"); + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_extensions_),\n"); } else { printer->Print("-1, // no _extensions_\n"); } // TODO(ckennelly): Consolidate this with the calculation for // AuxillaryParseTableField. - std::vector<string> package_parts; - - const Descriptor* outer = descriptor_; - while (outer->containing_type() != NULL) { - outer = outer->containing_type(); - } - - package_parts = Split( - outer->full_name(), ".", true); - // outer->full_name() contains the class itself. Remove it as it is - // used in the name of the default instance variable. - GOOGLE_DCHECK_NE(package_parts.size(), 0); - package_parts.back().clear(); - - vars["ns"] = Join(package_parts, "::"); + vars["ns"] = Namespace(descriptor_); printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classname$, _internal_metadata_),\n" - "&::$ns$_$classname$_default_instance_,\n"); + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, _internal_metadata_),\n" + "&$ns$::_$classname$_default_instance_,\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, "true,\n"); @@ -1717,15 +1510,14 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, int has_offset) { - if (IsMapEntryMessage(descriptor_)) return; - std::map<string, string> vars; - vars["classname"] = classname_; + vars["classname"] = QualifiedClassName(descriptor_); vars["offset"] = SimpleItoa(offset); - vars["has_bits_offsets"] = HasFieldPresence(descriptor_->file()) - ? SimpleItoa(offset + has_offset) - : "-1"; + vars["has_bits_offsets"] = + HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_) + ? SimpleItoa(offset + has_offset) + : "-1"; printer->Print(vars, "{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n"); @@ -1804,6 +1596,8 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { return 0; } + string full_classname = QualifiedClassName(descriptor_); + std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_); if (IsMapEntryMessage(descriptor_)) { for (int i = 0; i < 2; i++) { @@ -1812,9 +1606,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { field->number(), WireFormat::WireTypeForFieldType(field->type())); std::map<string, string> vars; - vars["classname"] = classname_; - vars["parent_classname"] = - ClassName(descriptor_->containing_type(), false); + vars["classname"] = QualifiedClassName(descriptor_); vars["field_name"] = FieldName(field); vars["tag"] = SimpleItoa(tag); vars["hasbit"] = SimpleItoa(i); @@ -1824,23 +1616,18 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); { vars["ptr"] = - QualifiedFileLevelSymbol( - field->message_type()->file()->package(), - FileLevelNamespace(field->message_type()->file()->name())) + + "::" + FileLevelNamespace(field->message_type()) + "::TableStruct::serialization_table + " + SimpleItoa(FindMessageIndexInFile(field->message_type())); } } - vars["extra"] = HasDescriptorMethods(descriptor_->file(), options_) - ? "::SuperType" - : ""; printer->Print(vars, "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$" - "classname$$extra$>, $field_name$_), $tag$," + "::google::protobuf::internal::MapEntryHelper<$classname$::" + "SuperType>, $field_name$_), $tag$," "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$" - "classname$$extra$>, _has_bits_) * 8 + $hasbit$, $type$, " + "::google::protobuf::internal::MapEntryHelper<$classname$::" + "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, " "$ptr$},\n"); } return 2; @@ -1848,7 +1635,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { printer->Print( "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " "_cached_size_), 0, 0, 0, NULL},\n", - "classname", classname_); + "classname", full_classname); std::vector<const Descriptor::ExtensionRange*> sorted_extensions; for (int i = 0; i < descriptor_->extension_range_count(); ++i) { sorted_extensions.push_back(descriptor_->extension_range(i)); @@ -1868,7 +1655,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { "::google::protobuf::internal::FieldMetadata::kSpecial, " "reinterpret_cast<const " "void*>(::google::protobuf::internal::ExtensionSerializer)},\n", - "classname", classname_, "start", SimpleItoa(range->start), "end", + "classname", full_classname, "start", SimpleItoa(range->start), "end", SimpleItoa(range->end)); } if (i == sorted.size()) break; @@ -1886,14 +1673,14 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { classfieldname = field->containing_oneof()->name(); } std::map<string, string> vars; - vars["classname"] = classname_; + vars["classname"] = full_classname; vars["field_name"] = classfieldname; vars["tag"] = SimpleItoa(tag); vars["ptr"] = "NULL"; if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (IsMapEntryMessage(field->message_type())) { vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type())); - vars["fieldclassname"] = ClassName(field->message_type(), false); + vars["fieldclassname"] = QualifiedClassName(field->message_type()); printer->Print(vars, "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" "classname$, $field_name$_), $tag$, $idx$, " @@ -1901,15 +1688,13 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { "reinterpret_cast<const void*>(static_cast< " "::google::protobuf::internal::SpecialSerializer>(" "::google::protobuf::internal::MapFieldSerializer< " - "::google::protobuf::internal::MapEntryToMapField<$classname$::$" - "fieldclassname$>::MapFieldType, " + "::google::protobuf::internal::MapEntryToMapField<" + "$fieldclassname$>::MapFieldType, " "TableStruct::serialization_table>))},\n"); continue; } else { vars["ptr"] = - QualifiedFileLevelSymbol( - field->message_type()->file()->package(), - FileLevelNamespace(field->message_type()->file()->name())) + + "::" + FileLevelNamespace(field->message_type()) + "::TableStruct::serialization_table + " + SimpleItoa(FindMessageIndexInFile(field->message_type())); } @@ -1960,40 +1745,20 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { "_internal_metadata_), 0, ~0u, " "::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const " "void*>($serializer$)},\n", - "classname", classname_, "serializer", serializer); + "classname", full_classname, "serializer", serializer); return num_field_metadata; } -void MessageGenerator:: -GenerateDefaultInstanceAllocator(io::Printer* printer) { - // Construct the default instances of all fields, as they will be used - // when creating the default instance of the entire message. +void MessageGenerator::GenerateFieldDefaultInstances(io::Printer* printer) { + // Construct the default instances for all fields that need one. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) .GenerateDefaultInstanceAllocator(printer); } - - // Construct the default instance. We can't call InitAsDefaultInstance() yet - // because we need to make sure all default instances that this one might - // depend on are constructed first. - printer->Print("_$classname$_default_instance_._instance.DefaultConstruct();\n" - "::google::protobuf::internal::OnShutdownDestroyMessage(\n" - " &_$classname$_default_instance_);", - "classname", classname_); } void MessageGenerator:: GenerateDefaultInstanceInitializer(io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) { - printer->Print( - "_$classname$_default_instance_._instance.get_mutable()->set_default_instance(_$" - "classname$_default_instance_._instance.get_mutable());\n" - "_$classname$_default_instance_._instance.get_mutable()->InitAsDefaultInstance();" - "\n", - "classname", classname_); - return; - } - // The default instance needs all of its embedded message pointers // cross-linked to other default instances. We can't do this initialization // in the constructor because some other default instances may not have been @@ -2016,10 +1781,11 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { } name += FieldName(field); printer->Print( - "$name$_ = const_cast< $type$*>(\n" + "$ns$::$name$_ = const_cast< $type$*>(\n" " $type$::internal_default_instance());\n", // Vars. - "name", name, "type", FieldMessageTypeName(field)); + "name", name, "type", FieldMessageTypeName(field), "ns", + Namespace(descriptor_)); } else if (field->containing_oneof() && HasDescriptorMethods(descriptor_->file(), options_)) { field_generators_.get(descriptor_->field(i)) @@ -2031,31 +1797,41 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) { + printer->Print( + "$classname$::$classname$() {}\n" + "$classname$::$classname$(::google::protobuf::Arena* arena) : " + "SuperType(arena) {}\n" + "void $classname$::MergeFrom(const $classname$& other) {\n" + " MergeFromInternal(other);\n" + "}\n", + "classname", classname_); if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - "$parent$::$classname$::$classname$() {}\n" - "$parent$::$classname$::$classname$(::google::protobuf::Arena* arena) : " - "SuperType(arena) {}\n" - "::google::protobuf::Metadata $parent$::$classname$::GetMetadata() const {\n" - " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return $file_namespace$::file_level_metadata[$index$];\n" + "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" + " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n" + " return ::$file_namespace$::file_level_metadata[$index$];\n" "}\n" - "void $parent$::$classname$::MergeFrom(\n" + "void $classname$::MergeFrom(\n" " const ::google::protobuf::Message& other) {\n" " ::google::protobuf::Message::MergeFrom(other);\n" "}\n" - "void $parent$::$classname$::MergeFrom(const $classname$& other) {\n" - " MergeFromInternal(other);\n" - "}\n" "\n", - "file_namespace", FileLevelNamespace(descriptor_->file()->name()), - "parent", ClassName(descriptor_->containing_type(), false), + "file_namespace", FileLevelNamespace(descriptor_), "classname", classname_, "index", SimpleItoa(index_in_file_messages_)); } return; } + // TODO(gerbens) Remove this function. With a little bit of cleanup and + // refactoring this is superfluous. + printer->Print("void $classname$::InitAsDefaultInstance() {\n", "classname", + classname_); + printer->Indent(); + GenerateDefaultInstanceInitializer(printer); + printer->Outdent(); + printer->Print("}\n"); + if (IsAnyMessage(descriptor_)) { printer->Print( "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" @@ -2134,23 +1910,24 @@ GenerateClassMethods(io::Printer* printer) { if (options_.table_driven_serialization) { printer->Print( - "const void* $classname$::InternalGetTable() const {\n" - " return $file_namespace$::TableStruct::serialization_table + $index$;\n" - "}\n" - "\n", - "classname", classname_, "index", SimpleItoa(index_in_file_messages_), - "file_namespace", FileLevelNamespace(descriptor_->file()->name())); + "const void* $classname$::InternalGetTable() const {\n" + " return ::$file_namespace$::TableStruct::serialization_table + " + "$index$;\n" + "}\n" + "\n", + "classname", classname_, "index", SimpleItoa(index_in_file_messages_), + "file_namespace", FileLevelNamespace(descriptor_)); } if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return " + " return ::" "$file_namespace$::file_level_metadata[kIndexInFileMessages];\n" "}\n" "\n", "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_->file()->name())); + FileLevelNamespace(descriptor_)); } else { printer->Print( "::std::string $classname$::GetTypeName() const {\n" @@ -2224,7 +2001,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { WireFormat::TagSize(field->number(), field->type()); std::map<string, string> vars; - vars["classname"] = classname_; + vars["classname"] = QualifiedClassName(descriptor_); if (field->containing_oneof() != NULL) { vars["name"] = field->containing_oneof()->name(); vars["presence"] = SimpleItoa(field->containing_oneof()->index()); @@ -2280,23 +2057,8 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { last_field_number++; break; case FieldDescriptor::CPPTYPE_MESSAGE: { - std::vector<string> package_parts; - - const Descriptor* outer = field->message_type(); - while (outer->containing_type() != NULL) { - outer = outer->containing_type(); - } - - package_parts = Split( - outer->full_name(), ".", true); - // outer->full_name() contains the class itself. Remove it as it is - // used in the name of the default instance variable. - GOOGLE_DCHECK_NE(package_parts.size(), 0); - package_parts.back().clear(); - if (field->is_map()) { - vars["classname"] = ClassName(field->containing_type(), false) + - "::" + ClassName(field->message_type(), false); + vars["classname"] = QualifiedClassName(field->message_type()); printer->Print(vars, "{::google::protobuf::internal::AuxillaryParseTableField::map_" "aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n"); @@ -2305,13 +2067,15 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { } else { vars["classname"] = ClassName(field->message_type(), false); } - vars["ns"] = Join(package_parts, "::"); + vars["ns"] = Namespace(field->message_type()); vars["type"] = FieldMessageTypeName(field); - vars["file_namespace"] = FileLevelNamespace(outer->file()->name()); + vars["file_namespace"] = + FileLevelNamespace(field->message_type()); - printer->Print(vars, + printer->Print( + vars, "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n" - " &::$ns$_$classname$_default_instance_,\n"); + " &$ns$::_$classname$_default_instance_,\n"); bool dont_emit_table = !TableDrivenParsingEnabled(field->message_type(), options_); @@ -2320,8 +2084,8 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { printer->Print(" NULL,\n"); } else { printer->Print(vars, - " ::$ns$$file_namespace$::TableStruct::schema +\n" - " ::$ns$$classname$::kIndexInFileMessages,\n"); + " ::$file_namespace$::TableStruct::schema +\n" + " $ns$::$classname$::kIndexInFileMessages,\n"); } printer->Print("}},\n"); @@ -2333,8 +2097,9 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { case FieldOptions::STRING: vars["default"] = field->default_value_string().empty() - ? "&::google::protobuf::internal::fixed_address_empty_string" - : "&" + classname_ + "::_default_" + FieldName(field) + "_"; + ? "&::google::protobuf::internal::fixed_address_empty_string" + : "&" + Namespace(field) + " ::" + classname_ + + "::_default_" + FieldName(field) + "_"; break; case FieldOptions::CORD: case FieldOptions::STRING_PIECE: @@ -2360,11 +2125,11 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) return std::make_pair(0, 0); std::map<string, string> variables; - variables["classname"] = classname_; + string full_classname = QualifiedClassName(descriptor_); + variables["classname"] = full_classname; - if (HasFieldPresence(descriptor_->file())) { + if (HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)) { printer->Print( variables, "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " @@ -2405,27 +2170,29 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->containing_oneof() || field->options().weak()) { - printer->Print( - "offsetof($classname$DefaultTypeInternal, $name$_),\n", - "classname", classname_, "name", FieldName(field)); + printer->Print("offsetof($classname$DefaultTypeInternal, $name$_),\n", + "classname", full_classname, "name", FieldName(field)); } else { printer->Print( "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "$name$_),\n", - "classname", classname_, - "name", FieldName(field)); + "$name$_),\n", + "classname", full_classname, "name", FieldName(field)); } } for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { const OneofDescriptor* oneof = descriptor_->oneof_decl(i); printer->Print( - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n", - "classname", classname_, - "name", oneof->name()); + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n", + "classname", full_classname, "name", oneof->name()); } - if (HasFieldPresence(descriptor_->file())) { + if (IsMapEntryMessage(descriptor_)) { + entries += 2; + printer->Print( + "0,\n" + "1,\n"); + } else if (HasFieldPresence(descriptor_->file())) { entries += has_bit_indices_.size(); for (int i = 0; i < has_bit_indices_.size(); i++) { const string index = has_bit_indices_[i] >= 0 ? @@ -2700,27 +2467,28 @@ GenerateStructors(io::Printer* printer) { "$classname$::$classname$()\n" " : $initializer$ {\n" " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n" - " $file_namespace$::InitDefaults();\n" + " ::$file_namespace$::InitDefaults$scc_name$();\n" " }\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", "classname", classname_, "full_name", descriptor_->full_name(), - "initializer", initializer_null, "file_namespace", - FileLevelNamespace(descriptor_->file()->name())); + "scc_name", scc_name_, "initializer", initializer_null, "file_namespace", + FileLevelNamespace(descriptor_)); if (SupportsArenas(descriptor_)) { printer->Print( "$classname$::$classname$(::google::protobuf::Arena* arena)\n" " : $initializer$ {\n" - " $file_namespace$::InitDefaults();\n" + " ::$file_namespace$::InitDefaults$scc_name$();\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" "}\n", "initializer", initializer_with_arena, "classname", classname_, "superclass", superclass, "full_name", descriptor_->full_name(), - "file_namespace", FileLevelNamespace(descriptor_->file()->name())); + "scc_name", scc_name_, "file_namespace", + FileLevelNamespace(descriptor_)); } // Generate the copy constructor. @@ -2865,23 +2633,23 @@ GenerateStructors(io::Printer* printer) { !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" - " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return " + " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n" + " return ::" "$file_namespace$::file_level_metadata[kIndexInFileMessages]." "descriptor;\n" "}\n" "\n", "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_->file()->name())); + FileLevelNamespace(descriptor_)); } printer->Print( "const $classname$& $classname$::default_instance() {\n" - " $file_namespace$::InitDefaults();\n" + " ::$file_namespace$::InitDefaults$scc_name$();\n" " return *internal_default_instance();\n" "}\n\n", - "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_->file()->name())); + "classname", classname_, "scc_name", scc_name_, "file_namespace", + FileLevelNamespace(descriptor_)); if (SupportsArenas(descriptor_)) { printer->Print( @@ -2930,6 +2698,9 @@ bool MessageGenerator::MaybeGenerateOptionalFieldCondition( void MessageGenerator:: GenerateClear(io::Printer* printer) { + // Performance tuning parameters + const int kMaxUnconditionalPrimitiveBytesClear = 4; + printer->Print( "void $classname$::Clear() {\n" "// @@protoc_insertion_point(message_clear_start:$full_name$)\n", @@ -2951,6 +2722,17 @@ GenerateClear(io::Printer* printer) { } int last_i = -1; + int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear; + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + + if (!CanInitializeByZeroing(field)) { + continue; + } + + unconditional_budget -= EstimateAlignmentSize(field); + } + for (int i = 0; i < optimized_order_.size(); ) { // Detect infinite loops. GOOGLE_CHECK_NE(i, last_i); @@ -2998,7 +2780,8 @@ GenerateClear(io::Printer* printer) { if (last_chunk == -1) { last_chunk = chunk; last_chunk_start = i; - } else if (chunk != last_chunk) { + } else if ((memset_run_start == -1 || unconditional_budget < 0) && + chunk != last_chunk) { // Emit the fields for this chunk so far. break; } @@ -3012,6 +2795,11 @@ GenerateClear(io::Printer* printer) { last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } + if (memset_run_start != memset_run_end && unconditional_budget >= 0) { + // Flush the memset fields. + goto flush; + } + // Step 4: Non-repeated, non-zero initializable fields. for (; i < optimized_order_.size(); i++) { const FieldDescriptor* field = optimized_order_[i]; @@ -3037,6 +2825,8 @@ GenerateClear(io::Printer* printer) { last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } +flush: + if (last_chunk != -1) { GOOGLE_DCHECK_NE(-1, last_chunk_start); GOOGLE_DCHECK_NE(-1, last_chunk_end); @@ -3044,7 +2834,10 @@ GenerateClear(io::Printer* printer) { const int count = popcnt(last_chunk_mask); const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end); + (last_chunk_start != last_chunk_end) && + (memset_run_start != last_chunk_start || + memset_run_end != last_chunk_end || + unconditional_budget < 0); if (have_outer_if) { // Check (up to) 8 has_bits at a time if we have more than one field in @@ -3613,12 +3406,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print( "return ::google::protobuf::internal::MergePartialFromCodedStream$lite$(\n" " this,\n" - " $file_namespace$::TableStruct::schema[\n" + " ::$file_namespace$::TableStruct::schema[\n" " $classname$::kIndexInFileMessages],\n" " input);\n", - "classname", classname_, - "file_namespace", FileLevelNamespace(descriptor_->file()->name()), - "lite", lite); + "classname", classname_, "file_namespace", + FileLevelNamespace(descriptor_), "lite", lite); printer->Outdent(); @@ -3631,17 +3423,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) { " ::google::protobuf::uint32 tag;\n"); if (!UseUnknownFieldSet(descriptor_->file(), options_)) { - // Use LazyStringOutputString to avoid initializing unknown fields string - // unless it is actually needed. For the same reason, disable eager refresh - // on the CodedOutputStream. printer->Print( - " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " ::google::protobuf::NewPermanentCallback(&_internal_metadata_,\n" - " &::google::protobuf::internal::InternalMetadataWithArenaLite::\n" - " mutable_unknown_fields));\n" - " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" - " &unknown_fields_string, false);\n", - "classname", classname_); + " ::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(\n" + " &_internal_metadata_);\n" + " ::google::protobuf::io::StringOutputStream unknown_fields_output(\n" + " unknown_fields_setter.buffer());\n" + " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" + " &unknown_fields_output, false);\n", + "classname", classname_); } printer->Print( diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 352069eb..cf64f483 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -43,6 +43,7 @@ #include <string> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h> #include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { @@ -62,12 +63,10 @@ class ExtensionGenerator; // extension.h class MessageGenerator { public: // See generator.cc for the meaning of dllexport_decl. - MessageGenerator(const Descriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer); + MessageGenerator(const Descriptor* descriptor, int index_in_file_messages, + const Options& options, SCCAnalyzer* scc_analyzer); ~MessageGenerator(); - // Appends the pre-order walk of the nested generators to list. - void Flatten(std::vector<MessageGenerator*>* list); // Append the two types of nested generators to the corresponding vector. void AddGenerators(std::vector<EnumGenerator*>* enum_generators, std::vector<ExtensionGenerator*>* extension_generators); @@ -96,8 +95,8 @@ class MessageGenerator { // Generate extra fields void GenerateExtraDefaultFields(io::Printer* printer); - // Generates code that allocates the message's default instance. - void GenerateDefaultInstanceAllocator(io::Printer* printer); + // Generates code that creates default instances for fields. + void GenerateFieldDefaultInstances(io::Printer* printer); // Generates code that initializes the message's default instance. This // is separate from allocating because all default instances must be @@ -208,6 +207,7 @@ class MessageGenerator { std::vector<uint32> RequiredFieldsBitMask() const; const Descriptor* descriptor_; + int index_in_file_messages_; string classname_; Options options_; FieldGeneratorMap field_generators_; @@ -218,7 +218,6 @@ class MessageGenerator { std::vector<const FieldDescriptor *> optimized_order_; std::vector<int> has_bit_indices_; int max_has_bit_index_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_; int num_required_fields_; @@ -227,9 +226,10 @@ class MessageGenerator { // table_driven_ indicates the generated message uses table-driven parsing. bool table_driven_; - int index_in_file_messages_; + google::protobuf::scoped_ptr<MessageLayoutHelper> message_layout_helper_; SCCAnalyzer* scc_analyzer_; + string scc_name_; friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index da4c3950..5888f51a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -45,13 +45,42 @@ namespace cpp { namespace { +// When we are generating code for implicit weak fields, we need to insert some +// additional casts. These functions return the casted expression if +// implicit_weak_field is true but otherwise return the original expression. +// Ordinarily a static_cast is enough to cast google::protobuf::MessageLite* to a class +// deriving from it, but we need a reinterpret_cast in cases where the generated +// message is forward-declared but its full definition is not visible. +string StaticCast(const string& type, const string& expression, + bool implicit_weak_field) { + if (implicit_weak_field) { + return "static_cast< " + type + " >(" + expression + ")"; + } else { + return expression; + } +} + +string ReinterpretCast(const string& type, const string& expression, + bool implicit_weak_field) { + if (implicit_weak_field) { + return "reinterpret_cast< " + type + " >(" + expression + ")"; + } else { + return expression; + } +} + void SetMessageVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["casted_member"] = + StaticCast((*variables)["type"] + "*", (*variables)["name"] + "_", + IsImplicitWeakField(descriptor, options)); (*variables)["type_default_instance"] = DefaultInstanceName(descriptor->message_type()); + (*variables)["type_reference_function"] = + ReferenceFunctionName(descriptor->message_type()); if (descriptor->options().weak() || !descriptor->containing_oneof()) { (*variables)["non_null_ptr_to_name"] = StrCat("this->", (*variables)["name"], "_"); @@ -85,7 +114,8 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) : FieldGenerator(options), descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + implicit_weak_field_(IsImplicitWeakField(descriptor, options)) { SetMessageVariables(descriptor, &variables_, options); } @@ -93,7 +123,11 @@ MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, "$type$* $name$_;\n"); + if (implicit_weak_field_) { + printer->Print(variables_, "google::protobuf::MessageLite* $name$_;\n"); + } else { + printer->Print(variables_, "$type$* $name$_;\n"); + } } void MessageFieldGenerator:: @@ -108,7 +142,11 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { if (!dependent_field_) { return; } - // Arena manipulation code is out-of-line in the derived message class. + // Arena manipulation code is out-of-line in the derived message class. The + // one exception is unsafe_arena_release_; this method has to be inline so + // that when the implicit weak field optimization is enabled, the method does + // not introduce a strong dependency on the submessage type unless the + // accessor actually gets called somewhere. printer->Print(variables_, "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); printer->Annotate("{", "}", descriptor_); @@ -118,14 +156,22 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { "$deprecated_attr$void ${$set_allocated_$name$$}$" "($type$* $name$);\n"); printer->Annotate("{", "}", descriptor_); + if (SupportsArenas(descriptor_)) { + printer->Print( + variables_, + "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + } } void MessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "private:\n" - "void _slow_mutable_$name$();\n"); + "private:\n"); + if (!implicit_weak_field_) { + printer->Print(variables_, "void _slow_mutable_$name$();\n"); + } if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, "void _slow_set_allocated_$name$(\n" @@ -135,6 +181,16 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$type$* _slow_$release_name$();\n" "public:\n"); } + if (implicit_weak_field_) { + // These private accessors are used by MergeFrom and + // MergePartialFromCodedStream, and their purpose is to provide access to + // the field without creating a strong dependency on the message type. + printer->Print(variables_, + "private:\n" + "const google::protobuf::MessageLite& _internal_$name$() const;\n" + "google::protobuf::MessageLite* _internal_mutable_$name$();\n" + "public:\n"); + } GenerateGetterDeclaration(printer); if (!dependent_field_) { printer->Print(variables_, @@ -146,12 +202,14 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$deprecated_attr$void ${$set_allocated_$name$$}$" "($type$* $name$);\n"); printer->Annotate("{", "}", descriptor_); + if (SupportsArenas(descriptor_)) { + printer->Print( + variables_, + "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + } } if (SupportsArenas(descriptor_)) { - printer->Print( - variables_, - "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); printer->Print(variables_, "$deprecated_attr$void " "${$unsafe_arena_set_allocated_$name$$}$(\n" @@ -162,9 +220,39 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( io::Printer* printer) const { - if (SupportsArenas(descriptor_)) { + if (implicit_weak_field_) { printer->Print(variables_, - "void $classname$::_slow_mutable_$name$() {\n"); + "const google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n" + " if ($name$_ != NULL) {\n" + " return *$name$_;\n" + " } else if (&$type_default_instance$ != NULL) {\n" + " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &$type_default_instance$);\n" + " } else {\n" + " return *reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &::google::protobuf::internal::implicit_weak_message_default_instance);\n" + " }\n" + "}\n"); + } + if (SupportsArenas(descriptor_)) { + if (implicit_weak_field_) { + printer->Print(variables_, + "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n" + " if (&$type_default_instance$ == NULL) {\n" + " $name$_ = ::google::protobuf::Arena::CreateMessage<\n" + " ::google::protobuf::internal::ImplicitWeakMessage>(\n" + " GetArenaNoVirtual());\n" + " } else {\n" + " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &$type_default_instance$)->New(GetArenaNoVirtual());\n" + " }\n" + " }\n" + " return $name$_;\n"); + } else { + printer->Print(variables_, + "void $classname$::_slow_mutable_$name$() {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" @@ -174,23 +262,27 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" " GetArenaNoVirtual());\n"); } + } printer->Print(variables_, "}\n" "$type$* $classname$::_slow_$release_name$() {\n" " if ($name$_ == NULL) {\n" " return NULL;\n" - " } else {\n" - " $type$* temp = new $type$(*$name$_);\n" - " $name$_ = NULL;\n" - " return temp;\n" + " } else {\n"); + if (implicit_weak_field_) { + printer->Print(variables_, + " google::protobuf::MessageLite* temp = $name$_->New();\n" + " temp->CheckTypeAndMergeFrom(*$name$_);\n"); + } else { + printer->Print(variables_, + " $type$* temp = new $type$(*$name$_);\n"); + } + printer->Print(variables_, " $name$_ = NULL;\n"); + printer->Print( + " return $result$;\n", "result", + StaticCast(variables_.at("type") + "*", "temp", implicit_weak_field_)); + printer->Print(variables_, " }\n" - "}\n" - "$type$* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" - " $clear_hasbit$\n" - " $type$* temp = $name$_;\n" - " $name$_ = NULL;\n" - " return temp;\n" "}\n"); if (SupportsArenas(descriptor_->message_type())) { // NOTE: the same logic is mirrored in weak_message_field.cc. Any @@ -202,12 +294,23 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n" " message_arena->Own(*$name$);\n" " } else if (message_arena !=\n" - " ::google::protobuf::Arena::GetArena(*$name$)) {\n" - " $type$* new_$name$ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " message_arena);\n" - " new_$name$->CopyFrom(**$name$);\n" - " *$name$ = new_$name$;\n" + " ::google::protobuf::Arena::GetArena(*$name$)) {\n"); + if (implicit_weak_field_) { + printer->Print(variables_, + " google::protobuf::MessageLite* new_$name$ =\n" + " reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &$type_default_instance$)->New(GetArenaNoVirtual());\n" + " new_$name$->CheckTypeAndMergeFrom(**$name$);\n" + " *$name$ = static_cast< $type$* >(new_$name$);\n"); + } else { + printer->Print(variables_, + " $type$* new_$name$ =\n" + " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " message_arena);\n" + " new_$name$->CopyFrom(**$name$);\n" + " *$name$ = new_$name$;\n"); + } + printer->Print(variables_, " }\n" "}\n"); } @@ -228,6 +331,20 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" ":$full_name$)\n" "}\n"); + } else if (implicit_weak_field_) { + printer->Print(variables_, + "google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n" + " if (&$type_default_instance$ == NULL) {\n" + " $name$_ = new ::google::protobuf::internal::ImplicitWeakMessage;\n" + " } else {\n" + " $name$_ = reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &$type_default_instance$)->New();\n" + " }\n" + " }\n" + " return $name$_;\n" + "}\n"); } } @@ -243,6 +360,10 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { variables["dependent_classname"] = DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; variables["this_message"] = DependentBaseDownCast(); + variables["casted_reference"] = + ReinterpretCast(variables["dependent_typename"] + "*&", + variables["this_message"] + variables["name"] + "_", + implicit_weak_field_); if (!variables["set_hasbit"].empty()) { variables["set_hasbit"] = variables["this_message"] + variables["set_hasbit"]; @@ -255,19 +376,39 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables, "template <class T>\n" - "inline $type$* $dependent_classname$::mutable_$name$() {\n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, " $set_hasbit$\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" - " if ($name$_ == NULL) {\n" - " $this_message$_slow_mutable_$name$();\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" + " if ($name$_ == NULL) {\n"); + if (implicit_weak_field_) { + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables, + " $name$_ = reinterpret_cast<$dependent_typename$*>(\n" + " reinterpret_cast<const google::protobuf::MessageLite*>(\n" + " &$type_default_instance$)->New(\n" + " $this_message$GetArenaNoVirtual()));\n"); + } + } else { + printer->Print(variables, + " $this_message$_slow_mutable_$name$();\n"); + } + printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" "template <class T>\n" "inline $type$* $dependent_classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, + " $dependent_typename$*& $name$_ = $casted_reference$;\n" " $clear_hasbit$\n" " if ($this_message$GetArenaNoVirtual() != NULL) {\n" " return $this_message$_slow_$release_name$();\n" @@ -281,7 +422,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "inline void $dependent_classname$::" "set_allocated_$name$($type$* $name$) {\n" " ::google::protobuf::Arena* message_arena = $this_message$GetArenaNoVirtual();\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" " if (message_arena == NULL) {\n" " delete $name$_;\n" " }\n" @@ -311,13 +452,27 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { " }\n" // TODO(dlj): move insertion points to message class. " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(" + "field_unsafe_arena_release:$full_name$)\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, + " $clear_hasbit$\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" "}\n"); } else { printer->Print(variables, "template <class T>\n" "inline $type$* $dependent_classname$::mutable_$name$() {\n" " $set_hasbit$\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" " if ($name$_ == NULL) {\n" " $name$_ = new $dependent_typename$;\n" " }\n" @@ -326,9 +481,13 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "template <class T>\n" "inline $type$* $dependent_classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, " $clear_hasbit$\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" " $dependent_typename$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" @@ -336,7 +495,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "template <class T>\n" "inline void $dependent_classname$::" "set_allocated_$name$($type$* $name$) {\n" - " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$*& $name$_ = $casted_reference$;\n" " delete $name$_;\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -366,9 +525,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; + variables["const_member"] = ReinterpretCast( + "const " + variables["type"] + "*", variables["name"] + "_", + implicit_weak_field_); printer->Print(variables, - "$inline$const $type$& $classname$::$name$() const {\n" - " const $type$* p = $name$_;\n" + "$inline$const $type$& $classname$::$name$() const {\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, + " const $type$* p = $const_member$;\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n" " &$type_default_instance$);\n" @@ -381,11 +547,18 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "$inline$" "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" - " if ($name$_ == NULL) {\n" - " _slow_mutable_$name$();\n" + " if ($name$_ == NULL) {\n"); + if (implicit_weak_field_) { + printer->Print(variables, + " _internal_mutable_$name$();\n"); + } else { + printer->Print(variables, + " _slow_mutable_$name$();\n"); + } + printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" + " return $casted_member$;\n" "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" @@ -394,7 +567,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" " } else {\n" - " $type$* temp = $name$_;\n" + " $type$* temp = $casted_member$;\n" " $name$_ = NULL;\n" " return temp;\n" " }\n" @@ -429,6 +602,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $clear_hasbit$\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "$inline$" + "$type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(" + "field_unsafe_arena_release:$full_name$)\n"); + if (implicit_weak_field_) { + printer->Print(variables, " $type_reference_function$();\n"); + } + printer->Print(variables, + " $clear_hasbit$\n" + " $type$* temp = $casted_member$;\n" + " $name$_ = NULL;\n" + " return temp;\n" "}\n"); } else { printer->Print(variables, @@ -439,13 +625,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $name$_ = new $type$;\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" + " return $casted_member$;\n" "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" - " $type$* temp = $name$_;\n" + " $type$* temp = $casted_member$;\n" " $name$_ = NULL;\n" " return temp;\n" "}\n" @@ -485,6 +671,9 @@ GenerateClearingCode(io::Printer* printer) const { "if ($this_message$GetArenaNoVirtual() == NULL && " "$this_message$$name$_ != NULL) delete $this_message$$name$_;\n" "$this_message$$name$_ = NULL;\n"); + } else if (implicit_weak_field_) { + printer->Print(variables, + "if ($this_message$$name$_ != NULL) $this_message$$name$_->Clear();\n"); } else { printer->Print(variables, "if ($this_message$$name$_ != NULL) $this_message$$name$_->" @@ -502,6 +691,10 @@ GenerateMessageClearingCode(io::Printer* printer) const { " delete $name$_;\n" "}\n" "$name$_ = NULL;\n"); + } else if (implicit_weak_field_) { + printer->Print(variables_, + "GOOGLE_DCHECK($name$_ != NULL);\n" + "$name$_->Clear();\n"); } else { printer->Print(variables_, "GOOGLE_DCHECK($name$_ != NULL);\n" @@ -511,8 +704,14 @@ GenerateMessageClearingCode(io::Printer* printer) const { void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); + if (implicit_weak_field_) { + printer->Print(variables_, + "_internal_mutable_$name$()->CheckTypeAndMergeFrom(\n" + " from._internal_$name$());\n"); + } else { + printer->Print(variables_, + "mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); + } } void MessageFieldGenerator:: @@ -557,17 +756,24 @@ GenerateCopyConstructorCode(io::Printer* printer) const { // wasn't copied, so both of these methods allocate the submessage on the // heap. - printer->Print(variables_, - "if (from.has_$name$()) {\n" - " $name$_ = new $type$(*from.$name$_);\n" - "} else {\n" - " $name$_ = NULL;\n" - "}\n"); + string new_expression = (implicit_weak_field_ ? "from.$name$_->New()" + : "new $type$(*from.$name$_)"); + string output = + "if (from.has_$name$()) {\n" + " $name$_ = " + new_expression + ";\n" + "} else {\n" + " $name$_ = NULL;\n" + "}\n"; + printer->Print(variables_, output.c_str()); } void MessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + if (implicit_weak_field_) { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n" + " input, _internal_mutable_$name$()));\n"); + } else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" " input, mutable_$name$()));\n"); @@ -595,9 +801,11 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { void MessageFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, + std::map<string, string> variables = variables_; + variables["no_virtual"] = (implicit_weak_field_ ? "" : "NoVirtual"); + printer->Print(variables, "total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n" + " ::google::protobuf::internal::WireFormatLite::$declared_type$Size$no_virtual$(\n" " *$non_null_ptr_to_name$);\n"); } @@ -771,13 +979,15 @@ void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions( " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::unsafe_arena_release_$name$() {\n" " // @@protoc_insertion_point(field_unsafe_arena_release" ":$full_name$)\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " $dependent_typename$* temp = $this_message$$oneof_prefix$$name$_;\n" + " $this_message$$oneof_prefix$$name$_ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index cd9737f0..14698992 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -44,6 +44,8 @@ namespace protobuf { namespace compiler { namespace cpp { +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options); + class MessageFieldGenerator : public FieldGenerator { public: MessageFieldGenerator(const FieldDescriptor* descriptor, @@ -78,6 +80,7 @@ class MessageFieldGenerator : public FieldGenerator { const FieldDescriptor* descriptor_; const bool dependent_field_; + const bool implicit_weak_field_; std::map<string, string> variables_; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h new file mode 100644 index 00000000..d502a6f0 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h @@ -0,0 +1,61 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: seongkim@google.com (Seong Beom Kim) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ + +#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Provides an abstract interface to optimize message layout +// by rearranging the fields of a message. +class MessageLayoutHelper { + public: + virtual ~MessageLayoutHelper() {} + + virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields, + const Options& options) = 0; +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 04338083..4a29ad0e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -39,6 +39,8 @@ namespace google { namespace protobuf { namespace compiler { +class AccessInfoMap; + namespace cpp { // Generator options (see generator.cc for a description of each): @@ -50,7 +52,9 @@ struct Options { annotate_headers(false), enforce_lite(false), table_driven_parsing(false), - table_driven_serialization(false) {} + table_driven_serialization(false), + lite_implicit_weak_fields(false), + access_info_map(NULL) {} string dllexport_decl; bool safe_boundary_check; @@ -60,8 +64,10 @@ struct Options { bool enforce_lite; bool table_driven_parsing; bool table_driven_serialization; + bool lite_implicit_weak_fields; string annotation_pragma_name; string annotation_guard_name; + const AccessInfoMap* access_info_map; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc new file mode 100644 index 00000000..e9303865 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc @@ -0,0 +1,220 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> + +#include <google/protobuf/compiler/cpp/cpp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +namespace { + +// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of +// fields that are grouped together because they have compatible alignment, and +// a preferred location in the final field ordering. +class FieldGroup { + public: + FieldGroup() : preferred_location_(0) {} + + // A group with a single field. + FieldGroup(float preferred_location, const FieldDescriptor* field) + : preferred_location_(preferred_location), fields_(1, field) {} + + // Append the fields in 'other' to this group. + void Append(const FieldGroup& other) { + if (other.fields_.empty()) { + return; + } + // Preferred location is the average among all the fields, so we weight by + // the number of fields on each FieldGroup object. + preferred_location_ = (preferred_location_ * fields_.size() + + (other.preferred_location_ * other.fields_.size())) / + (fields_.size() + other.fields_.size()); + fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end()); + } + + void SetPreferredLocation(float location) { preferred_location_ = location; } + const std::vector<const FieldDescriptor*>& fields() const { return fields_; } + + // FieldGroup objects sort by their preferred location. + bool operator<(const FieldGroup& other) const { + return preferred_location_ < other.preferred_location_; + } + + private: + // "preferred_location_" is an estimate of where this group should go in the + // final list of fields. We compute this by taking the average index of each + // field in this group in the original ordering of fields. This is very + // approximate, but should put this group close to where its member fields + // originally went. + float preferred_location_; + std::vector<const FieldDescriptor*> fields_; + // We rely on the default copy constructor and operator= so this type can be + // used in a vector. +}; + +} // namespace + +// Reorder 'fields' so that if the fields are output into a c++ class in the new +// order, fields of similar family (see below) are together and within each +// family, alignment padding is minimized. +// +// We try to do this while keeping each field as close as possible to its field +// number order so that we don't reduce cache locality much for function that +// access each field in order. Originally, OptimizePadding used declaration +// order for its decisions, but generated code minus the serializer/parsers uses +// the output of OptimizePadding as well (stored in +// MessageGenerator::optimized_order_). Since the serializers use field number +// order, we use that as a tie-breaker. +// +// We classify each field into a particular "family" of fields, that we perform +// the same operation on in our generated functions. +// +// REPEATED is placed first, as the C++ compiler automatically initializes +// these fields in layout order. +// +// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and +// calls ArenaStringPtr::Destroy on each. +// +// +// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls +// delete on each. We initialize these fields with a NULL pointer (see +// MessageFieldGenerator::GenerateConstructorCode), which allows them to be +// memset. +// +// ZERO_INITIALIZABLE is memset in Clear/SharedCtor +// +// OTHER these fields are initialized one-by-one. +void PaddingOptimizer::OptimizeLayout( + std::vector<const FieldDescriptor*>* fields, const Options& options) { + // The sorted numeric order of Family determines the declaration order in the + // memory layout. + enum Family { + REPEATED = 0, + STRING = 1, + MESSAGE = 3, + ZERO_INITIALIZABLE = 4, + OTHER = 5, + kMaxFamily + }; + + // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. + std::vector<FieldGroup> aligned_to_1[kMaxFamily]; + std::vector<FieldGroup> aligned_to_4[kMaxFamily]; + std::vector<FieldGroup> aligned_to_8[kMaxFamily]; + for (int i = 0; i < fields->size(); ++i) { + const FieldDescriptor* field = (*fields)[i]; + + Family f = OTHER; + if (field->is_repeated()) { + f = REPEATED; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + f = STRING; + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + f = MESSAGE; + + } else if (CanInitializeByZeroing(field)) { + f = ZERO_INITIALIZABLE; + } + + const int j = field->number(); + switch (EstimateAlignmentSize(field)) { + case 1: + aligned_to_1[f].push_back(FieldGroup(j, field)); + break; + case 4: + aligned_to_4[f].push_back(FieldGroup(j, field)); + break; + case 8: + aligned_to_8[f].push_back(FieldGroup(j, field)); + break; + default: + GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field) + << "for a field " << field->full_name() << "."; + } + } + + // For each family, group fields to optimize padding. + for (int f = 0; f < kMaxFamily; f++) { + // Now group fields aligned to 1 byte into sets of 4, and treat those like a + // single field aligned to 4 bytes. + for (int i = 0; i < aligned_to_1[f].size(); i += 4) { + FieldGroup field_group; + for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) { + field_group.Append(aligned_to_1[f][j]); + } + aligned_to_4[f].push_back(field_group); + } + // Sort by preferred location to keep fields as close to their field number + // order as possible. Using stable_sort ensures that the output is + // consistent across runs. + std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end()); + + // Now group fields aligned to 4 bytes (or the 4-field groups created above) + // into pairs, and treat those like a single field aligned to 8 bytes. + for (int i = 0; i < aligned_to_4[f].size(); i += 2) { + FieldGroup field_group; + for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) { + field_group.Append(aligned_to_4[f][j]); + } + if (i == aligned_to_4[f].size() - 1) { + if (f == OTHER) { + // Move incomplete 4-byte block to the beginning. This is done to + // pair with the (possible) leftover blocks from the + // ZERO_INITIALIZABLE family. + field_group.SetPreferredLocation(-1); + } else { + // Move incomplete 4-byte block to the end. + field_group.SetPreferredLocation(fields->size() + 1); + } + } + aligned_to_8[f].push_back(field_group); + } + // Sort by preferred location. + std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end()); + } + + // Now pull out all the FieldDescriptors in order. + fields->clear(); + for (int f = 0; f < kMaxFamily; ++f) { + for (int i = 0; i < aligned_to_8[f].size(); ++i) { + fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(), + aligned_to_8[f][i].fields().end()); + } + } +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h new file mode 100644 index 00000000..9641ba40 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: seongkim@google.com (Seong Beom Kim) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ + +#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Rearranges the fields of a message to minimize padding. +// Fields are grouped by the type and the size. +// For example, grouping four boolean fields and one int32 +// field results in zero padding overhead. See OptimizeLayout's +// comment for details. +class PaddingOptimizer : public MessageLayoutHelper { + public: + PaddingOptimizer() {} + ~PaddingOptimizer() {} + + void OptimizeLayout(std::vector<const FieldDescriptor*>* fields, + const Options& options); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index b05fcc4e..67cfc405 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -245,9 +245,8 @@ GenerateSwappingCode(io::Printer* printer) const { void PrimitiveOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print( - variables_, - "_$classname$_default_instance_.$name$_ = $default$;\n"); + printer->Print(variables_, + "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); } void PrimitiveOneofFieldGenerator:: @@ -433,7 +432,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" " target);\n" " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n" - " static_cast< ::google::protobuf::uint32>(\n" + " static_cast< ::google::protobuf::int32>(\n" " _$name$_cached_byte_size_), target);\n" " target = ::google::protobuf::internal::WireFormatLite::\n" " Write$declared_type$NoTagToArray(this->$name$_, target);\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index fec13b6d..8e675751 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -58,8 +58,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["default_variable"] = descriptor->default_value_string().empty() ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()" - : "&" + (*variables)["classname"] + "::" + default_variable_string + - ".get()"; + : "&" + Namespace(descriptor) + "::" + (*variables)["classname"] + + "::" + default_variable_string + ".get()"; (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; (*variables)["null_check"] = "GOOGLE_DCHECK(value != NULL);\n"; @@ -71,6 +71,9 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["full_name"] = descriptor->full_name(); (*variables)["string_piece"] = "::std::string"; + + (*variables)["lite"] = + HasDescriptorMethods(descriptor->file(), options) ? "" : "Lite"; } } // namespace @@ -79,7 +82,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(options), descriptor_(descriptor), + lite_(!HasDescriptorMethods(descriptor->file(), options)) { SetStringVariables(descriptor, &variables_, options); } @@ -207,13 +211,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n" "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" " $set_hasbit$\n" - " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" + " $name$_.Set$lite$($default_variable$, value, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" "$inline$void $classname$::set_$name$(::std::string&& value) {\n" " $set_hasbit$\n" - " $name$_.Set(\n" + " $name$_.Set$lite$(\n" " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" "}\n" @@ -221,7 +225,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "$inline$void $classname$::set_$name$(const char* value) {\n" " $null_check$" " $set_hasbit$\n" - " $name$_.Set($default_variable$, $string_piece$(value),\n" + " $name$_.Set$lite$($default_variable$, $string_piece$(value),\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" @@ -229,7 +233,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" " $set_hasbit$\n" - " $name$_.Set($default_variable$, $string_piece$(\n" + " $name$_.Set$lite$($default_variable$, $string_piece$(\n" " reinterpret_cast<const char*>(value), size), " "GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" @@ -453,7 +457,7 @@ GenerateCopyConstructorCode(io::Printer* printer) const { if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) { // TODO(gpike): improve this printer->Print(variables_, - "$name$_.Set($default_variable$, from.$name$(),\n" + "$name$_.Set$lite$($default_variable$, from.$name$(),\n" " GetArenaNoVirtual());\n"); } else { printer->Print(variables_, @@ -480,13 +484,14 @@ GenerateDestructorCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$classname$::$default_variable_name$.DefaultConstruct();\n" - "*$classname$::$default_variable_name$.get_mutable() = " - "::std::string($default$, $default_length$);\n" - "::google::protobuf::internal::OnShutdownDestroyString(\n" - " $classname$::$default_variable_name$.get_mutable());\n" - ); + printer->Print( + variables_, + "$ns$::$classname$::$default_variable_name$.DefaultConstruct();\n" + "*$ns$::$classname$::$default_variable_name$.get_mutable() = " + "::std::string($default$, $default_length$);\n" + "::google::protobuf::internal::OnShutdownDestroyString(\n" + " $ns$::$classname$::$default_variable_name$.get_mutable());\n" + ); } } @@ -572,7 +577,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " set_has_$name$();\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set($default_variable$, value,\n" + " $oneof_prefix$$name$_.Set$lite$($default_variable$, value,\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" @@ -584,7 +589,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " set_has_$name$();\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set(\n" + " $oneof_prefix$$name$_.Set$lite$(\n" " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" "}\n" @@ -596,7 +601,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " set_has_$name$();\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set($default_variable$,\n" + " $oneof_prefix$$name$_.Set$lite$($default_variable$,\n" " $string_piece$(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n" @@ -608,7 +613,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " set_has_$name$();\n" " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" " }\n" - " $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n" + " $oneof_prefix$$name$_.Set$lite$(\n" + " $default_variable$, $string_piece$(\n" " reinterpret_cast<const char*>(value), size),\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" @@ -806,7 +812,7 @@ void StringOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { printer->Print( variables_, - "_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n" + "$ns$::_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n" " $default_variable$);\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 531252b0..933f3c6b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -73,6 +73,7 @@ class StringFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; std::map<string, string> variables_; + const bool lite_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index 4e25b2ea..7fe98759 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -151,6 +151,10 @@ enum ConflictingEnum { // NO_PROTO3 message DummyMessage {} +// Message names that could conflict. +message Shutdown {} +message TableStruct {} + service TestConflictingMethodNames { rpc Closure(DummyMessage) returns (DummyMessage); } diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index fdde771b..61cc32a4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -744,21 +744,6 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) { TestUtil::ExpectAllFieldsSet(message1); } -#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \ - !defined(GOOGLE_PROTOBUF_NO_RTTI) -#ifdef PROTOBUF_HAS_DEATH_TEST -#ifndef NDEBUG - -TEST(GeneratedMessageTest, MergeFromSelf) { - unittest::TestAllTypes message; - EXPECT_DEATH(message.MergeFrom(message), "pb[.]cc.*Check failed:"); - EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)), - "pb[.]cc.*Check failed:"); -} - -#endif // NDEBUG -#endif // PROTOBUF_HAS_DEATH_TEST -#endif // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI // Test the generated SerializeWithCachedSizesToArray(), TEST(GeneratedMessageTest, SerializationToArray) { diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc index 4c357aa0..9792ffe8 100644 --- a/src/google/protobuf/compiler/importer.cc +++ b/src/google/protobuf/compiler/importer.cc @@ -54,13 +54,17 @@ #include <google/protobuf/compiler/parser.h> #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/stubs/io_win32.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/io_win32.h> #ifdef _WIN32 #include <ctype.h> #endif +namespace google { +namespace protobuf { +namespace compiler { + #ifdef _MSC_VER // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import // them like we do below. @@ -68,10 +72,6 @@ using google::protobuf::internal::win32::access; using google::protobuf::internal::win32::open; #endif -namespace google { -namespace protobuf { -namespace compiler { - // Returns true if the text looks like a Windows-style absolute path, starting // with a drive letter. Example: "C:\foo". TODO(kenton): Share this with // copy in command_line_interface.cc? diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index bd565ced..1ab168c4 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -136,6 +136,13 @@ inline string ShortMutableJavaClassName(const Descriptor* descriptor) { return descriptor->name(); } +// Whether the given descriptor is for one of the core descriptor protos. We +// cannot currently use the new runtime with core protos since there is a +// bootstrapping problem with obtaining their descriptors. +inline bool IsDescriptorProto(const Descriptor* descriptor) { + return descriptor->file()->name() == "google/protobuf/descriptor.proto"; +} + // Whether we should generate multiple java files for messages. inline bool MultipleJavaFiles( @@ -371,6 +378,10 @@ inline bool IsAnyMessage(const Descriptor* descriptor) { return descriptor->full_name() == "google.protobuf.Any"; } +inline bool IsWrappersProtoFile(const FileDescriptor* descriptor) { + return descriptor->name() == "google/protobuf/wrappers.proto"; +} + inline bool CheckUtf8(const FieldDescriptor* descriptor) { return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || descriptor->file()->options().java_string_check_utf8(); @@ -379,6 +390,10 @@ inline bool CheckUtf8(const FieldDescriptor* descriptor) { inline string GeneratedCodeVersionSuffix() { return "V3"; } + +inline bool EnableExperimentalRuntime(Context* context) { + return false; +} } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index ecc67575..df0c95c8 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -379,7 +379,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "}\n"); if (context_->HasGeneratedMethods(descriptor_)) { - GenerateParsingConstructor(printer); + if (!EnableExperimentalRuntime(context_) || + IsDescriptorProto(descriptor_)) { + GenerateParsingConstructor(printer); + } } GenerateDescriptorMethods(printer); @@ -537,6 +540,17 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); + // 'of' method for Wrappers + if (IsWrappersProtoFile(descriptor_->file())) { + printer->Print( + "public static $classname$ of($field_type$ value) {\n" + " return newBuilder().setValue(value).build();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0)))); + } + GenerateParser(printer); printer->Print( @@ -576,95 +590,103 @@ GenerateMessageSerializationMethods(io::Printer* printer) { "public void writeTo(com.google.protobuf.CodedOutputStream output)\n" " throws java.io.IOException {\n"); printer->Indent(); - if (HasPackedFields(descriptor_)) { - // writeTo(CodedOutputStream output) might be invoked without - // getSerializedSize() ever being called, but we need the memoized - // sizes in case this message has packed fields. Rather than emit checks for - // each packed field, just call getSerializedSize() up front. - // In most cases, getSerializedSize() will have already been called anyway - // by one of the wrapper writeTo() methods, making this call cheap. - printer->Print( - "getSerializedSize();\n"); - } - if (descriptor_->extension_range_count() > 0) { - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "com.google.protobuf.GeneratedMessage$ver$\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newMessageSetExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "ver", GeneratedCodeVersionSuffix()); - } else { - printer->Print( - "com.google.protobuf.GeneratedMessage$ver$\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "ver", GeneratedCodeVersionSuffix()); + if (EnableExperimentalRuntime(context_) && !IsDescriptorProto(descriptor_)) { + printer->Print("writeToInternal(output);\n"); + } else { + if (HasPackedFields(descriptor_)) { + // writeTo(CodedOutputStream output) might be invoked without + // getSerializedSize() ever being called, but we need the memoized + // sizes in case this message has packed fields. Rather than emit checks + // for each packed field, just call getSerializedSize() up front. In most + // cases, getSerializedSize() will have already been called anyway by one + // of the wrapper writeTo() methods, making this call cheap. + printer->Print("getSerializedSize();\n"); } - } - // Merge the fields and the extension ranges, both sorted by field number. - for (int i = 0, j = 0; - i < descriptor_->field_count() || j < sorted_extensions.size(); - ) { - if (i == descriptor_->field_count()) { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); - } else if (j == sorted_extensions.size()) { - GenerateSerializeOneField(printer, sorted_fields[i++]); - } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) { - GenerateSerializeOneField(printer, sorted_fields[i++]); - } else { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print( + "com.google.protobuf.GeneratedMessage$ver$\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newMessageSetExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "ver", GeneratedCodeVersionSuffix()); + } else { + printer->Print( + "com.google.protobuf.GeneratedMessage$ver$\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "ver", GeneratedCodeVersionSuffix()); + } } - } - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "unknownFields.writeAsMessageSetTo(output);\n"); - } else { - printer->Print( - "unknownFields.writeTo(output);\n"); + // Merge the fields and the extension ranges, both sorted by field number. + for (int i = 0, j = 0; + i < descriptor_->field_count() || j < sorted_extensions.size();) { + if (i == descriptor_->field_count()) { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } else if (j == sorted_extensions.size()) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } + } + + if (descriptor_->options().message_set_wire_format()) { + printer->Print("unknownFields.writeAsMessageSetTo(output);\n"); + } else { + printer->Print("unknownFields.writeTo(output);\n"); + } } printer->Outdent(); printer->Print( - "}\n" - "\n" - "public int getSerializedSize() {\n" - " int size = memoizedSize;\n" - " if (size != -1) return size;\n" - "\n" - " size = 0;\n"); + "}\n" + "\n" + "public int getSerializedSize() {\n" + " int size = memoizedSize;\n" + " if (size != -1) return size;\n" + "\n"); printer->Indent(); + if (EnableExperimentalRuntime(context_) && !IsDescriptorProto(descriptor_)) { + printer->Print( + "memoizedSize = getSerializedSizeInternal();\n" + "return memoizedSize;\n"); + } else { - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); - } + printer->Print("size = 0;\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]) + .GenerateSerializedSizeCode(printer); + } + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print("size += extensionsSerializedSizeAsMessageSet();\n"); + } else { + printer->Print("size += extensionsSerializedSize();\n"); + } + } - if (descriptor_->extension_range_count() > 0) { if (descriptor_->options().message_set_wire_format()) { printer->Print( - "size += extensionsSerializedSizeAsMessageSet();\n"); + "size += unknownFields.getSerializedSizeAsMessageSet();\n"); } else { - printer->Print( - "size += extensionsSerializedSize();\n"); + printer->Print("size += unknownFields.getSerializedSize();\n"); } - } - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "size += unknownFields.getSerializedSizeAsMessageSet();\n"); - } else { printer->Print( - "size += unknownFields.getSerializedSize();\n"); + "memoizedSize = size;\n" + "return size;\n"); } printer->Outdent(); printer->Print( - " memoizedSize = size;\n" - " return size;\n" "}\n" "\n"); } @@ -1199,7 +1221,10 @@ GenerateParsingConstructor(io::Printer* printer) { // Initialize all fields to default. printer->Print( - "this();\n"); + "this();\n" + "if (extensionRegistry == null) {\n" + " throw new java.lang.NullPointerException();\n" + "}\n"); // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; @@ -1335,10 +1360,18 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n", "classname", descriptor_->name()); - if (context_->HasGeneratedMethods(descriptor_)) { + if (EnableExperimentalRuntime(context_) && !IsDescriptorProto(descriptor_)) { + printer->Indent(); printer->Print( - " return new $classname$(input, extensionRegistry);\n", + "$classname$ msg = new $classname$();\n" + "msg.mergeFromInternal(input, extensionRegistry);\n" + "msg.makeImmutableInternal();\n" + "return msg;\n", "classname", descriptor_->name()); + printer->Outdent(); + } else if (context_->HasGeneratedMethods(descriptor_)) { + printer->Print(" return new $classname$(input, extensionRegistry);\n", + "classname", descriptor_->name()); } else { // When parsing constructor isn't generated, use builder to parse // messages. Note, will fallback to use reflection based mergeFieldFrom() diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 26f16439..29b4f98b 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -332,17 +332,19 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - GenerateMessageSerializationMethods(printer); + if (!EnableExperimentalRuntime(context_)) { + GenerateMessageSerializationMethods(printer); + } GenerateParseFromMethods(printer); GenerateBuilder(printer); if (HasRequiredFields(descriptor_)) { // Memoizes whether the protocol buffer is fully initialized (has all - // required fields). -1 means not yet computed. 0 means false and 1 means - // true. + // required fields). 0 means false, 1 means true, and all other values + // mean not yet computed. printer->Print( - "private byte memoizedIsInitialized = -1;\n"); + "private byte memoizedIsInitialized = 2;\n"); } printer->Print( @@ -415,13 +417,33 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { " }\n" " }\n" " }\n" - " return PARSER;\n" - "}\n", + " return PARSER;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Outdent(); - printer->Outdent(); + if (HasRequiredFields(descriptor_)) { + printer->Print( + "}\n" + "case GET_MEMOIZED_IS_INITIALIZED: {\n" + " return memoizedIsInitialized;\n" + "}\n" + "case SET_MEMOIZED_IS_INITIALIZED: {\n" + " memoizedIsInitialized = (byte) (arg0 == null ? 0 : 1);\n" + " return null;\n" + "}\n"); + } else { + printer->Print( + "}\n" + "case GET_MEMOIZED_IS_INITIALIZED: {\n" + " return (byte) 1;\n" + "}\n" + "case SET_MEMOIZED_IS_INITIALIZED: {\n" + " return null;\n" + "}\n"); + } + + printer->Outdent(); printer->Print( " }\n" " throw new UnsupportedOperationException();\n" @@ -455,6 +477,17 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); + // 'of' method for Wrappers + if (IsWrappersProtoFile(descriptor_->file())) { + printer->Print( + "public static $classname$ of($field_type$ value) {\n" + " return newBuilder().setValue(value).build();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "field_type", PrimitiveTypeName(GetJavaType(descriptor_->field(0)))); + } + GenerateParser(printer); // Extensions must be declared after the DEFAULT_INSTANCE is initialized @@ -490,36 +523,34 @@ GenerateMessageSerializationMethods(io::Printer* printer) { if (HasPackedFields(descriptor_)) { // writeTo(CodedOutputStream output) might be invoked without // getSerializedSize() ever being called, but we need the memoized - // sizes in case this message has packed fields. Rather than emit checks for - // each packed field, just call getSerializedSize() up front. - // In most cases, getSerializedSize() will have already been called anyway - // by one of the wrapper writeTo() methods, making this call cheap. - printer->Print( - "getSerializedSize();\n"); + // sizes in case this message has packed fields. Rather than emit checks + // for each packed field, just call getSerializedSize() up front. In most + // cases, getSerializedSize() will have already been called anyway by one + // of the wrapper writeTo() methods, making this call cheap. + printer->Print("getSerializedSize();\n"); } if (descriptor_->extension_range_count() > 0) { if (descriptor_->options().message_set_wire_format()) { printer->Print( - "com.google.protobuf.GeneratedMessageLite\n" - " .ExtendableMessage<$classname$, $classname$.Builder>\n" - " .ExtensionWriter extensionWriter =\n" - " newMessageSetExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + "com.google.protobuf.GeneratedMessageLite\n" + " .ExtendableMessage<$classname$, $classname$.Builder>\n" + " .ExtensionWriter extensionWriter =\n" + " newMessageSetExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } else { printer->Print( - "com.google.protobuf.GeneratedMessageLite\n" - " .ExtendableMessage<$classname$, $classname$.Builder>\n" - " .ExtensionWriter extensionWriter =\n" - " newExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + "com.google.protobuf.GeneratedMessageLite\n" + " .ExtendableMessage<$classname$, $classname$.Builder>\n" + " .ExtensionWriter extensionWriter =\n" + " newExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } } // Merge the fields and the extension ranges, both sorted by field number. for (int i = 0, j = 0; - i < descriptor_->field_count() || j < sorted_extensions.size(); - ) { + i < descriptor_->field_count() || j < sorted_extensions.size();) { if (i == descriptor_->field_count()) { GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); } else if (j == sorted_extensions.size()) { @@ -532,23 +563,22 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "unknownFields.writeAsMessageSetTo(output);\n"); + printer->Print("unknownFields.writeAsMessageSetTo(output);\n"); } else { - printer->Print( - "unknownFields.writeTo(output);\n"); + printer->Print("unknownFields.writeTo(output);\n"); } printer->Outdent(); printer->Print( - "}\n" - "\n" - "public int getSerializedSize() {\n" - " int size = memoizedSerializedSize;\n" - " if (size != -1) return size;\n" - "\n" - " size = 0;\n"); + "}\n" + "\n" + "public int getSerializedSize() {\n" + " int size = memoizedSerializedSize;\n" + " if (size != -1) return size;\n" + "\n"); printer->Indent(); + printer->Print( + "size = 0;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); @@ -556,26 +586,24 @@ GenerateMessageSerializationMethods(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "size += extensionsSerializedSizeAsMessageSet();\n"); + printer->Print("size += extensionsSerializedSizeAsMessageSet();\n"); } else { - printer->Print( - "size += extensionsSerializedSize();\n"); + printer->Print("size += extensionsSerializedSize();\n"); } } if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "size += unknownFields.getSerializedSizeAsMessageSet();\n"); + printer->Print("size += unknownFields.getSerializedSizeAsMessageSet();\n"); } else { - printer->Print( - "size += unknownFields.getSerializedSize();\n"); + printer->Print("size += unknownFields.getSerializedSize();\n"); } + printer->Print( + "memoizedSerializedSize = size;\n" + "return size;\n"); + printer->Outdent(); printer->Print( - " memoizedSerializedSize = size;\n" - " return size;\n" "}\n" "\n"); } @@ -702,7 +730,10 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( return; } - // Don't directly compare to -1 to avoid an Android x86 JIT bug. + // TODO(xiaofeng): Remove this when b/64445758 is fixed. We don't need to + // check memoizedIsInitialized here because the caller does that already, + // but right now proguard proto shrinker asserts on the bytecode layout of + // this code so it can't be removed until proguard is updated. printer->Print( "byte isInitialized = memoizedIsInitialized;\n" "if (isInitialized == 1) return DEFAULT_INSTANCE;\n" @@ -720,9 +751,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( if (field->is_required()) { printer->Print( "if (!has$name$()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" "}\n", "name", info->capitalized_name); @@ -739,9 +767,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( case FieldDescriptor::LABEL_REQUIRED: printer->Print( "if (!get$name$().isInitialized()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" "}\n", "type", name_resolver_->GetImmutableClassName( @@ -765,9 +790,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( } printer->Print( " if (!get$name$().isInitialized()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" " }\n" "}\n", @@ -778,9 +800,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( printer->Print( "for ($type$ item : get$name$Map().values()) {\n" " if (!item.isInitialized()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" " }\n" "}\n", @@ -791,9 +810,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( printer->Print( "for (int i = 0; i < get$name$Count(); i++) {\n" " if (!get$name$(i).isInitialized()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" " }\n" "}\n", @@ -809,17 +825,11 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( if (descriptor_->extension_range_count() > 0) { printer->Print( "if (!extensionsAreInitialized()) {\n" - " if (shouldMemoize) {\n" - " memoizedIsInitialized = 0;\n" - " }\n" " return null;\n" "}\n"); } printer->Print( - "if (shouldMemoize) memoizedIsInitialized = 1;\n"); - - printer->Print( "return DEFAULT_INSTANCE;\n" "\n"); } @@ -946,99 +956,107 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream( "com.google.protobuf.CodedInputStream input =\n" " (com.google.protobuf.CodedInputStream) arg0;\n" "com.google.protobuf.ExtensionRegistryLite extensionRegistry =\n" - " (com.google.protobuf.ExtensionRegistryLite) arg1;\n"); + " (com.google.protobuf.ExtensionRegistryLite) arg1;\n" + "if (extensionRegistry == null) {\n" + " throw new java.lang.NullPointerException();\n" + "}\n"); printer->Print( "try {\n"); printer->Indent(); - printer->Print( - "boolean done = false;\n" - "while (!done) {\n"); - printer->Indent(); - - printer->Print( - "int tag = input.readTag();\n" - "switch (tag) {\n"); - printer->Indent(); + if (EnableExperimentalRuntime(context_)) { + printer->Print( + "mergeFromInternal(input, extensionRegistry);\n" + "return DEFAULT_INSTANCE;\n"); + } else { + printer->Print( + "boolean done = false;\n" + "while (!done) {\n"); + printer->Indent(); - printer->Print( - "case 0:\n" // zero signals EOF / limit reached - " done = true;\n" - " break;\n"); + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); - if (descriptor_->extension_range_count() > 0) { - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "default: {\n" - " if (!parseUnknownFieldAsMessageSet(\n" - " getDefaultInstanceForType(), input, extensionRegistry,\n" - " tag)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n"); + printer->Print( + "case 0:\n" // zero signals EOF / limit reached + " done = true;\n" + " break;\n"); + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print( + "default: {\n" + " if (!parseUnknownFieldAsMessageSet(\n" + " getDefaultInstanceForType(), input, extensionRegistry,\n" + " tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } else { + printer->Print( + "default: {\n" + " if (!parseUnknownField(getDefaultInstanceForType(),\n" + " input, extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } } else { printer->Print( "default: {\n" - " if (!parseUnknownField(getDefaultInstanceForType(),\n" - " input, extensionRegistry, tag)) {\n" + " if (!parseUnknownField(tag, input)) {\n" " done = true;\n" // it's an endgroup tag " }\n" " break;\n" "}\n"); } - } else { - printer->Print( - "default: {\n" - " if (!parseUnknownField(tag, input)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n"); - } - google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields( - SortFieldsByNumber(descriptor_)); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = sorted_fields[i]; - uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForFieldType(field->type())); - - printer->Print( - "case $tag$: {\n", - "tag", SimpleItoa(static_cast<int32>(tag))); - printer->Indent(); - - field_generators_.get(field).GenerateParsingCode(printer); - - printer->Outdent(); - printer->Print( - " break;\n" - "}\n"); + google::protobuf::scoped_array<const FieldDescriptor* > sorted_fields( + SortFieldsByNumber(descriptor_)); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32 tag = WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); - if (field->is_packable()) { - // To make packed = true wire compatible, we generate parsing code from a - // packed version of this field regardless of field->options().packed(). - uint32 packed_tag = WireFormatLite::MakeTag(field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED); - printer->Print( - "case $tag$: {\n", - "tag", SimpleItoa(static_cast<int32>(packed_tag))); + printer->Print("case $tag$: {\n", "tag", + SimpleItoa(static_cast<int32>(tag))); printer->Indent(); - field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + field_generators_.get(field).GenerateParsingCode(printer); printer->Outdent(); printer->Print( " break;\n" "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from + // a packed version of this field regardless of + // field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag( + field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print("case $tag$: {\n", "tag", + SimpleItoa(static_cast<int32>(packed_tag))); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } } - } - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" // switch (tag) - "}\n"); // while (!done) + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + "}\n"); // while (!done) + } printer->Outdent(); printer->Print( diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc index f73bfb04..9a42aba9 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -140,13 +140,16 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { "java.lang.String[] descriptorData = {\n"); printer->Indent(); - // Only write 40 bytes per line. + // Limit the number of bytes per line. static const int kBytesPerLine = 40; + // Limit the number of lines per string part. + static const int kLinesPerPart = 400; + // Every block of bytes, start a new string literal, in order to avoid the + // 64k length limit. Note that this value needs to be <64k. + static const int kBytesPerPart = kBytesPerLine * kLinesPerPart; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { if (i > 0) { - // Every 400 lines, start a new string literal, in order to avoid the - // 64k length limit. - if (i % 400 == 0) { + if (i % kBytesPerPart == 0) { printer->Print(",\n"); } else { printer->Print(" +\n"); diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index 73d32762..812ca9d8 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -1082,6 +1082,40 @@ string JSReturnClause(const FieldDescriptor* desc) { return ""; } +string JSTypeTag(const FieldDescriptor* desc) { + switch (desc->type()) { + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + if (IsIntegralFieldWithStringJSType(desc)) { + return "StringInt"; + } else { + return "Int"; + } + case FieldDescriptor::TYPE_BOOL: + return "Boolean"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + default: + assert(false); + } + return ""; +} + string JSReturnDoc(const GeneratorOptions& options, const FieldDescriptor* desc) { return ""; @@ -2569,26 +2603,44 @@ void Generator::GenerateClassField(const GeneratorOptions& options, /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field)); } - printer->Print( - "$class$.prototype.set$name$ = function(value) {\n" - " jspb.Message.set$oneoftag$Field(this, $index$", - "class", GetMessagePath(options, field->containing_type()), - "name", JSGetterName(options, field), - "oneoftag", (field->containing_oneof() ? "Oneof" : ""), - "index", JSFieldIndex(field)); - printer->Print( - "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" - "};\n" - "\n" - "\n", - "type", - untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", - "typeclose", untyped ? ")" : "", - "oneofgroup", - (field->containing_oneof() ? (", " + JSOneofArray(options, field)) - : ""), - "returnvalue", JSReturnClause(field), "rptvalueinit", - (field->is_repeated() ? " || []" : "")); + + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + !field->is_repeated() && !field->is_map() && + !HasFieldPresence(options, field)) { + // Proto3 non-repeated and non-map fields without presence use the + // setProto3*Field function. + printer->Print( + "$class$.prototype.set$name$ = function(value) {\n" + " jspb.Message.setProto3$typetag$Field(this, $index$, " + "value);$returnvalue$\n" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), "name", + JSGetterName(options, field), "typetag", JSTypeTag(field), "index", + JSFieldIndex(field), "returnvalue", JSReturnClause(field)); + } else { + // Otherwise, use the regular setField function. + printer->Print( + "$class$.prototype.set$name$ = function(value) {\n" + " jspb.Message.set$oneoftag$Field(this, $index$", + "class", GetMessagePath(options, field->containing_type()), "name", + JSGetterName(options, field), "oneoftag", + (field->containing_oneof() ? "Oneof" : ""), "index", + JSFieldIndex(field)); + printer->Print( + "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" + "};\n" + "\n" + "\n", + "type", + untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", + (field->containing_oneof() ? (", " + JSOneofArray(options, field)) + : ""), + "returnvalue", JSReturnClause(field), "rptvalueinit", + (field->is_repeated() ? " || []" : "")); + } if (untyped) { printer->Print( diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc index cc660f4a..bfcb83df 100644 --- a/src/google/protobuf/compiler/mock_code_generator.cc +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -57,12 +57,12 @@ #include <google/protobuf/stubs/substitute.h> #include <gtest/gtest.h> -#ifdef major -#undef major -#endif -#ifdef minor -#undef minor -#endif +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index bb4a44c3..03d05ad4 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -1540,7 +1540,6 @@ bool Parser::ParseReserved(DescriptorProto* message, } } - bool Parser::ParseReservedNames(DescriptorProto* message, const LocationRecorder& parent_location) { do { @@ -1601,6 +1600,81 @@ bool Parser::ParseReservedNumbers(DescriptorProto* message, return true; } +bool Parser::ParseReserved(EnumDescriptorProto* message, + const LocationRecorder& message_location) { + // Parse the declaration. + DO(Consume("reserved")); + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + LocationRecorder location(message_location, + DescriptorProto::kReservedNameFieldNumber); + return ParseReservedNames(message, location); + } else { + LocationRecorder location(message_location, + DescriptorProto::kReservedRangeFieldNumber); + return ParseReservedNumbers(message, location); + } +} + +bool Parser::ParseReservedNames(EnumDescriptorProto* message, + const LocationRecorder& parent_location) { + do { + LocationRecorder location(parent_location, message->reserved_name_size()); + DO(ConsumeString(message->add_reserved_name(), "Expected enum value.")); + } while (TryConsume(",")); + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseReservedNumbers(EnumDescriptorProto* message, + const LocationRecorder& parent_location) { + bool first = true; + do { + LocationRecorder location(parent_location, message->reserved_range_size()); + + EnumDescriptorProto::EnumReservedRange* range = + message->add_reserved_range(); + int start, end; + io::Tokenizer::Token start_token; + { + LocationRecorder start_location( + location, EnumDescriptorProto::EnumReservedRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeSignedInteger(&start, (first ? + "Expected enum value or number range." : + "Expected enum number range."))); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber); + if (TryConsume("max")) { + // This is in the enum descriptor path, which doesn't have the message + // set duality to fix up, so it doesn't integrate with the sentinel. + + // Evaluate 'max' to INT_MAX - 1 so that incrementing to create the + // exclusive range end doesn't cause an overflow. + // Note, this prevents reserving the actual INT_MAX enum value. + end = INT_MAX; + } else { + DO(ConsumeSignedInteger(&end, "Expected integer.")); + } + } else { + LocationRecorder end_location( + location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + range->set_start(start); + range->set_end(end); + first = false; + } while (TryConsume(",")); + + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, RepeatedPtrField<DescriptorProto>* messages, const LocationRecorder& parent_location, @@ -1781,6 +1855,8 @@ bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type, EnumDescriptorProto::kOptionsFieldNumber); return ParseOption(enum_type->mutable_options(), location, containing_file, OPTION_STATEMENT); + } else if (LookingAt("reserved")) { + return ParseReserved(enum_type, enum_location); } else { LocationRecorder location(enum_location, EnumDescriptorProto::kValueFieldNumber, enum_type->value_size()); @@ -2167,4 +2243,5 @@ void SourceLocationTable::Clear() { } // namespace compiler } // namespace protobuf + } // namespace google diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index dd8b6586..33b4c700 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -371,6 +371,12 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& parent_location); bool ParseReservedNumbers(DescriptorProto* message, const LocationRecorder& parent_location); + bool ParseReserved(EnumDescriptorProto* message, + const LocationRecorder& message_location); + bool ParseReservedNames(EnumDescriptorProto* message, + const LocationRecorder& parent_location); + bool ParseReservedNumbers(EnumDescriptorProto* message, + const LocationRecorder& parent_location); // Parse an "extend" declaration. (See also comments for // ParseMessageField().) diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 97831f71..9b59842e 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -994,6 +994,42 @@ TEST_F(ParseEnumTest, ValueOptions) { "}"); } +TEST_F(ParseEnumTest, ReservedRange) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 0;\n" + " reserved -2147483648, -6 to -4, -1 to 1, 2, 15, 9 to 11, 3, 20 to max;\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:0 }" + " reserved_range { start:-2147483648 end:-2147483648 }" + " reserved_range { start:-6 end:-4 }" + " reserved_range { start:-1 end:1 }" + " reserved_range { start:2 end:2 }" + " reserved_range { start:15 end:15 }" + " reserved_range { start:9 end:11 }" + " reserved_range { start:3 end:3 }" + " reserved_range { start:20 end:2147483647 }" + "}"); +} + +TEST_F(ParseEnumTest, ReservedNames) { + ExpectParsesTo( + "enum TestEnum {\n" + " FOO = 0;\n" + " reserved \"foo\", \"bar\";\n" + "}\n", + + "enum_type {" + " name: \"TestEnum\"" + " value { name:\"FOO\" number:0 }" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + "}"); +} + // =================================================================== typedef ParserTest ParseServiceTest; @@ -1488,6 +1524,51 @@ TEST_F(ParseErrorTest, EnumValueMissingNumber) { "1:5: Missing numeric value for enum constant.\n"); } +TEST_F(ParseErrorTest, EnumReservedStandaloneMaxNotAllowed) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved max;\n" + "}\n", + "2:11: Expected enum value or number range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedMixNameAndNumber) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved 10, \"foo\";\n" + "}\n", + "2:15: Expected enum number range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedPositiveNumberOutOfRange) { + ExpectHasErrors( + "enum TestEnum {\n" + "FOO = 1;\n" + " reserved 2147483648;\n" + "}\n", + "2:11: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedNegativeNumberOutOfRange) { + ExpectHasErrors( + "enum TestEnum {\n" + "FOO = 1;\n" + " reserved -2147483649;\n" + "}\n", + "2:12: Integer out of range.\n"); +} + +TEST_F(ParseErrorTest, EnumReservedMissingQuotes) { + ExpectHasErrors( + "enum TestEnum {\n" + " FOO = 1;\n" + " reserved foo;\n" + "}\n", + "2:11: Expected enum value or number range.\n"); +} + // ------------------------------------------------------------------- // Reserved field number errors @@ -1515,6 +1596,23 @@ TEST_F(ParseErrorTest, ReservedMissingQuotes) { "1:11: Expected field name or number range.\n"); } +TEST_F(ParseErrorTest, ReservedNegativeNumber) { + ExpectHasErrors( + "message Foo {\n" + " reserved -10;\n" + "}\n", + "1:11: Expected field name or number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedNumberOutOfRange) { + ExpectHasErrors( + "message Foo {\n" + " reserved 2147483648;\n" + "}\n", + "1:11: Integer out of range.\n"); +} + + // ------------------------------------------------------------------- // Service errors diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index cb5e37bb..7f975510 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -41,13 +41,18 @@ #include <unistd.h> #endif -#include <google/protobuf/stubs/io_win32.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/plugin.pb.h> #include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/stubs/io_win32.h> + + +namespace google { +namespace protobuf { +namespace compiler { #if defined(_MSC_VER) // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import @@ -55,10 +60,6 @@ using google::protobuf::internal::win32::setmode; #endif -namespace google { -namespace protobuf { -namespace compiler { - class GeneratorResponseContext : public GeneratorContext { public: GeneratorResponseContext( diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 07883a37..557e2d7a 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: google/protobuf/compiler/plugin.proto -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION #include <google/protobuf/compiler/plugin.pb.h> #include <algorithm> @@ -16,121 +15,168 @@ #include <google/protobuf/reflection_ops.h> #include <google/protobuf/wire_format.h> // @@protoc_insertion_point(includes) - namespace google { namespace protobuf { namespace compiler { class VersionDefaultTypeInternal { -public: - ::google::protobuf::internal::ExplicitlyConstructed<Version> - _instance; + public: + ::google::protobuf::internal::ExplicitlyConstructed<Version> + _instance; } _Version_default_instance_; class CodeGeneratorRequestDefaultTypeInternal { -public: - ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorRequest> - _instance; + public: + ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorRequest> + _instance; } _CodeGeneratorRequest_default_instance_; class CodeGeneratorResponse_FileDefaultTypeInternal { -public: - ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse_File> - _instance; + public: + ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse_File> + _instance; } _CodeGeneratorResponse_File_default_instance_; class CodeGeneratorResponseDefaultTypeInternal { -public: - ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse> - _instance; + public: + ::google::protobuf::internal::ExplicitlyConstructed<CodeGeneratorResponse> + _instance; } _CodeGeneratorResponse_default_instance_; - +} // namespace compiler +} // namespace protobuf +} // namespace google namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto { +void InitDefaultsVersionImpl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + ::google::protobuf::internal::InitProtobufDefaults(); + { + void* ptr = &::google::protobuf::compiler::_Version_default_instance_; + new (ptr) ::google::protobuf::compiler::Version(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::google::protobuf::compiler::Version::InitAsDefaultInstance(); +} -namespace { +void InitDefaultsVersion() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsVersionImpl); +} -::google::protobuf::Metadata file_level_metadata[4]; +void InitDefaultsCodeGeneratorRequestImpl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; -} // namespace + ::google::protobuf::internal::InitProtobufDefaults(); + protobuf_google_2fprotobuf_2fdescriptor_2eproto::InitDefaultsFileDescriptorProto(); + protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsVersion(); + { + void* ptr = &::google::protobuf::compiler::_CodeGeneratorRequest_default_instance_; + new (ptr) ::google::protobuf::compiler::CodeGeneratorRequest(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::google::protobuf::compiler::CodeGeneratorRequest::InitAsDefaultInstance(); +} -PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField - const TableStruct::entries[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - {0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0}, -}; +void InitDefaultsCodeGeneratorRequest() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsCodeGeneratorRequestImpl); +} -PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField - const TableStruct::aux[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - ::google::protobuf::internal::AuxillaryParseTableField(), -}; -PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const - TableStruct::schema[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - { NULL, NULL, 0, -1, -1, -1, -1, NULL, false }, - { NULL, NULL, 0, -1, -1, -1, -1, NULL, false }, - { NULL, NULL, 0, -1, -1, -1, -1, NULL, false }, - { NULL, NULL, 0, -1, -1, -1, -1, NULL, false }, -}; +void InitDefaultsCodeGeneratorResponse_FileImpl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::internal::InitProtobufDefaults(); + { + void* ptr = &::google::protobuf::compiler::_CodeGeneratorResponse_File_default_instance_; + new (ptr) ::google::protobuf::compiler::CodeGeneratorResponse_File(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::google::protobuf::compiler::CodeGeneratorResponse_File::InitAsDefaultInstance(); +} -const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, _has_bits_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, _internal_metadata_), +void InitDefaultsCodeGeneratorResponse_File() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsCodeGeneratorResponse_FileImpl); +} + +void InitDefaultsCodeGeneratorResponseImpl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::internal::InitProtobufDefaults(); + protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse_File(); + { + void* ptr = &::google::protobuf::compiler::_CodeGeneratorResponse_default_instance_; + new (ptr) ::google::protobuf::compiler::CodeGeneratorResponse(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::google::protobuf::compiler::CodeGeneratorResponse::InitAsDefaultInstance(); +} + +void InitDefaultsCodeGeneratorResponse() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsCodeGeneratorResponseImpl); +} + +::google::protobuf::Metadata file_level_metadata[4]; + +const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, _has_bits_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, major_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, minor_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, patch_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Version, suffix_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, major_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, minor_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, patch_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::Version, suffix_), 1, 2, 3, 0, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, _has_bits_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, file_to_generate_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, parameter_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, proto_file_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, compiler_version_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, file_to_generate_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, parameter_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, proto_file_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, compiler_version_), ~0u, 0, ~0u, 1, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse_File, _has_bits_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse_File, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, insertion_point_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, content_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse_File, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse_File, insertion_point_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse_File, content_), 0, 1, 2, - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse, _has_bits_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse, _internal_metadata_), ~0u, // no _extensions_ ~0u, // no _oneof_case_ ~0u, // no _weak_field_map_ - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, file_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse, error_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse, file_), 0, ~0u, }; -static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - { 0, 9, sizeof(Version)}, - { 13, 22, sizeof(CodeGeneratorRequest)}, - { 26, 34, sizeof(CodeGeneratorResponse_File)}, - { 37, 44, sizeof(CodeGeneratorResponse)}, +static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + { 0, 9, sizeof(::google::protobuf::compiler::Version)}, + { 13, 22, sizeof(::google::protobuf::compiler::CodeGeneratorRequest)}, + { 26, 34, sizeof(::google::protobuf::compiler::CodeGeneratorResponse_File)}, + { 37, 44, sizeof(::google::protobuf::compiler::CodeGeneratorResponse)}, }; static ::google::protobuf::Message const * const file_default_instances[] = { - reinterpret_cast<const ::google::protobuf::Message*>(&_Version_default_instance_), - reinterpret_cast<const ::google::protobuf::Message*>(&_CodeGeneratorRequest_default_instance_), - reinterpret_cast<const ::google::protobuf::Message*>(&_CodeGeneratorResponse_File_default_instance_), - reinterpret_cast<const ::google::protobuf::Message*>(&_CodeGeneratorResponse_default_instance_), + reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::compiler::_Version_default_instance_), + reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::compiler::_CodeGeneratorRequest_default_instance_), + reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::compiler::_CodeGeneratorResponse_File_default_instance_), + reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::compiler::_CodeGeneratorResponse_default_instance_), }; -namespace { - void protobuf_AssignDescriptors() { AddDescriptors(); ::google::protobuf::MessageFactory* factory = NULL; @@ -144,38 +190,15 @@ void protobuf_AssignDescriptorsOnce() { ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors); } -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; +void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD; void protobuf_RegisterTypes(const ::std::string&) { protobuf_AssignDescriptorsOnce(); ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 4); } -} // namespace -void TableStruct::InitDefaultsImpl() { - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::internal::InitProtobufDefaults(); - ::google::protobuf::protobuf_google_2fprotobuf_2fdescriptor_2eproto::InitDefaults(); - _Version_default_instance_._instance.DefaultConstruct(); - ::google::protobuf::internal::OnShutdownDestroyMessage( - &_Version_default_instance_);_CodeGeneratorRequest_default_instance_._instance.DefaultConstruct(); - ::google::protobuf::internal::OnShutdownDestroyMessage( - &_CodeGeneratorRequest_default_instance_);_CodeGeneratorResponse_File_default_instance_._instance.DefaultConstruct(); - ::google::protobuf::internal::OnShutdownDestroyMessage( - &_CodeGeneratorResponse_File_default_instance_);_CodeGeneratorResponse_default_instance_._instance.DefaultConstruct(); - ::google::protobuf::internal::OnShutdownDestroyMessage( - &_CodeGeneratorResponse_default_instance_);_CodeGeneratorRequest_default_instance_._instance.get_mutable()->compiler_version_ = const_cast< ::google::protobuf::compiler::Version*>( - ::google::protobuf::compiler::Version::internal_default_instance()); -} - -void InitDefaults() { - static GOOGLE_PROTOBUF_DECLARE_ONCE(once); - ::google::protobuf::GoogleOnceInit(&once, &TableStruct::InitDefaultsImpl); -} -namespace { void AddDescriptorsImpl() { InitDefaults(); - static const char descriptor[] GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { "\n%google/protobuf/compiler/plugin.proto\022" "\030google.protobuf.compiler\032 google/protob" "uf/descriptor.proto\"F\n\007Version\022\r\n\005major\030" @@ -197,9 +220,8 @@ void AddDescriptorsImpl() { descriptor, 638); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes); - ::google::protobuf::protobuf_google_2fprotobuf_2fdescriptor_2eproto::AddDescriptors(); + ::protobuf_google_2fprotobuf_2fdescriptor_2eproto::AddDescriptors(); } -} // anonymous namespace void AddDescriptors() { static GOOGLE_PROTOBUF_DECLARE_ONCE(once); @@ -211,12 +233,15 @@ struct StaticDescriptorInitializer { AddDescriptors(); } } static_descriptor_initializer; - } // namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto - +namespace google { +namespace protobuf { +namespace compiler { // =================================================================== +void Version::InitAsDefaultInstance() { +} #if !defined(_MSC_VER) || _MSC_VER >= 1900 const int Version::kMajorFieldNumber; const int Version::kMinorFieldNumber; @@ -227,7 +252,7 @@ const int Version::kSuffixFieldNumber; Version::Version() : ::google::protobuf::Message(), _internal_metadata_(NULL) { if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsVersion(); } SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.Version) @@ -271,12 +296,12 @@ void Version::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_END(); } const ::google::protobuf::Descriptor* Version::descriptor() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; } const Version& Version::default_instance() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsVersion(); return *internal_default_instance(); } @@ -599,151 +624,16 @@ void Version::InternalSwap(Version* other) { ::google::protobuf::Metadata Version::GetMetadata() const { protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Version - -// optional int32 major = 1; -bool Version::has_major() const { - return (_has_bits_[0] & 0x00000002u) != 0; -} -void Version::set_has_major() { - _has_bits_[0] |= 0x00000002u; -} -void Version::clear_has_major() { - _has_bits_[0] &= ~0x00000002u; -} -void Version::clear_major() { - major_ = 0; - clear_has_major(); -} -::google::protobuf::int32 Version::major() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.major) - return major_; -} -void Version::set_major(::google::protobuf::int32 value) { - set_has_major(); - major_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.major) -} - -// optional int32 minor = 2; -bool Version::has_minor() const { - return (_has_bits_[0] & 0x00000004u) != 0; -} -void Version::set_has_minor() { - _has_bits_[0] |= 0x00000004u; -} -void Version::clear_has_minor() { - _has_bits_[0] &= ~0x00000004u; -} -void Version::clear_minor() { - minor_ = 0; - clear_has_minor(); -} -::google::protobuf::int32 Version::minor() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.minor) - return minor_; -} -void Version::set_minor(::google::protobuf::int32 value) { - set_has_minor(); - minor_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.minor) + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; } -// optional int32 patch = 3; -bool Version::has_patch() const { - return (_has_bits_[0] & 0x00000008u) != 0; -} -void Version::set_has_patch() { - _has_bits_[0] |= 0x00000008u; -} -void Version::clear_has_patch() { - _has_bits_[0] &= ~0x00000008u; -} -void Version::clear_patch() { - patch_ = 0; - clear_has_patch(); -} -::google::protobuf::int32 Version::patch() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.patch) - return patch_; -} -void Version::set_patch(::google::protobuf::int32 value) { - set_has_patch(); - patch_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.patch) -} - -// optional string suffix = 4; -bool Version::has_suffix() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -void Version::set_has_suffix() { - _has_bits_[0] |= 0x00000001u; -} -void Version::clear_has_suffix() { - _has_bits_[0] &= ~0x00000001u; -} -void Version::clear_suffix() { - suffix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_suffix(); -} -const ::std::string& Version::suffix() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.suffix) - return suffix_.GetNoArena(); -} -void Version::set_suffix(const ::std::string& value) { - set_has_suffix(); - suffix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.suffix) -} -#if LANG_CXX11 -void Version::set_suffix(::std::string&& value) { - set_has_suffix(); - suffix_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.Version.suffix) -} -#endif -void Version::set_suffix(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_suffix(); - suffix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.Version.suffix) -} -void Version::set_suffix(const char* value, size_t size) { - set_has_suffix(); - suffix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.Version.suffix) -} -::std::string* Version::mutable_suffix() { - set_has_suffix(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.Version.suffix) - return suffix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* Version::release_suffix() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.Version.suffix) - clear_has_suffix(); - return suffix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void Version::set_allocated_suffix(::std::string* suffix) { - if (suffix != NULL) { - set_has_suffix(); - } else { - clear_has_suffix(); - } - suffix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), suffix); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.Version.suffix) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== +void CodeGeneratorRequest::InitAsDefaultInstance() { + ::google::protobuf::compiler::_CodeGeneratorRequest_default_instance_._instance.get_mutable()->compiler_version_ = const_cast< ::google::protobuf::compiler::Version*>( + ::google::protobuf::compiler::Version::internal_default_instance()); +} #if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorRequest::kFileToGenerateFieldNumber; const int CodeGeneratorRequest::kParameterFieldNumber; @@ -754,7 +644,7 @@ const int CodeGeneratorRequest::kCompilerVersionFieldNumber; CodeGeneratorRequest::CodeGeneratorRequest() : ::google::protobuf::Message(), _internal_metadata_(NULL) { if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorRequest(); } SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest) @@ -801,12 +691,12 @@ void CodeGeneratorRequest::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_END(); } const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; } const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorRequest(); return *internal_default_instance(); } @@ -1150,224 +1040,14 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) { ::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const { protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; } -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// CodeGeneratorRequest - -// repeated string file_to_generate = 1; -int CodeGeneratorRequest::file_to_generate_size() const { - return file_to_generate_.size(); -} -void CodeGeneratorRequest::clear_file_to_generate() { - file_to_generate_.Clear(); -} -const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - return file_to_generate_.Get(index); -} -::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - return file_to_generate_.Mutable(index); -} -void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - file_to_generate_.Mutable(index)->assign(value); -} -#if LANG_CXX11 -void CodeGeneratorRequest::set_file_to_generate(int index, ::std::string&& value) { - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - file_to_generate_.Mutable(index)->assign(std::move(value)); -} -#endif -void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { - GOOGLE_DCHECK(value != NULL); - file_to_generate_.Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { - file_to_generate_.Mutable(index)->assign( - reinterpret_cast<const char*>(value), size); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -::std::string* CodeGeneratorRequest::add_file_to_generate() { - // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - return file_to_generate_.Add(); -} -void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { - file_to_generate_.Add()->assign(value); - // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -#if LANG_CXX11 -void CodeGeneratorRequest::add_file_to_generate(::std::string&& value) { - file_to_generate_.Add(std::move(value)); - // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -#endif -void CodeGeneratorRequest::add_file_to_generate(const char* value) { - GOOGLE_DCHECK(value != NULL); - file_to_generate_.Add()->assign(value); - // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { - file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size); - // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) -} -const ::google::protobuf::RepeatedPtrField< ::std::string>& -CodeGeneratorRequest::file_to_generate() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - return file_to_generate_; -} -::google::protobuf::RepeatedPtrField< ::std::string>* -CodeGeneratorRequest::mutable_file_to_generate() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) - return &file_to_generate_; -} - -// optional string parameter = 2; -bool CodeGeneratorRequest::has_parameter() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -void CodeGeneratorRequest::set_has_parameter() { - _has_bits_[0] |= 0x00000001u; -} -void CodeGeneratorRequest::clear_has_parameter() { - _has_bits_[0] &= ~0x00000001u; -} -void CodeGeneratorRequest::clear_parameter() { - parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_parameter(); -} -const ::std::string& CodeGeneratorRequest::parameter() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter) - return parameter_.GetNoArena(); -} -void CodeGeneratorRequest::set_parameter(const ::std::string& value) { - set_has_parameter(); - parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter) -} -#if LANG_CXX11 -void CodeGeneratorRequest::set_parameter(::std::string&& value) { - set_has_parameter(); - parameter_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorRequest.parameter) -} -#endif -void CodeGeneratorRequest::set_parameter(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_parameter(); - parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter) -} -void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { - set_has_parameter(); - parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter) -} -::std::string* CodeGeneratorRequest::mutable_parameter() { - set_has_parameter(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter) - return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* CodeGeneratorRequest::release_parameter() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter) - clear_has_parameter(); - return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { - if (parameter != NULL) { - set_has_parameter(); - } else { - clear_has_parameter(); - } - parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter) -} - -// repeated .google.protobuf.FileDescriptorProto proto_file = 15; -int CodeGeneratorRequest::proto_file_size() const { - return proto_file_.size(); -} -void CodeGeneratorRequest::clear_proto_file() { - proto_file_.Clear(); -} -const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_.Get(index); -} -::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_.Mutable(index); -} -::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { - // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_.Add(); -} -::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* -CodeGeneratorRequest::mutable_proto_file() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return &proto_file_; -} -const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -CodeGeneratorRequest::proto_file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_; -} - -// optional .google.protobuf.compiler.Version compiler_version = 3; -bool CodeGeneratorRequest::has_compiler_version() const { - return (_has_bits_[0] & 0x00000002u) != 0; -} -void CodeGeneratorRequest::set_has_compiler_version() { - _has_bits_[0] |= 0x00000002u; -} -void CodeGeneratorRequest::clear_has_compiler_version() { - _has_bits_[0] &= ~0x00000002u; -} -void CodeGeneratorRequest::clear_compiler_version() { - if (compiler_version_ != NULL) compiler_version_->::google::protobuf::compiler::Version::Clear(); - clear_has_compiler_version(); -} -const ::google::protobuf::compiler::Version& CodeGeneratorRequest::compiler_version() const { - const ::google::protobuf::compiler::Version* p = compiler_version_; - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) - return p != NULL ? *p : *reinterpret_cast<const ::google::protobuf::compiler::Version*>( - &::google::protobuf::compiler::_Version_default_instance_); -} -::google::protobuf::compiler::Version* CodeGeneratorRequest::mutable_compiler_version() { - set_has_compiler_version(); - if (compiler_version_ == NULL) { - compiler_version_ = new ::google::protobuf::compiler::Version; - } - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) - return compiler_version_; -} -::google::protobuf::compiler::Version* CodeGeneratorRequest::release_compiler_version() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) - clear_has_compiler_version(); - ::google::protobuf::compiler::Version* temp = compiler_version_; - compiler_version_ = NULL; - return temp; -} -void CodeGeneratorRequest::set_allocated_compiler_version(::google::protobuf::compiler::Version* compiler_version) { - delete compiler_version_; - compiler_version_ = compiler_version; - if (compiler_version) { - set_has_compiler_version(); - } else { - clear_has_compiler_version(); - } - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.compiler_version) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== +void CodeGeneratorResponse_File::InitAsDefaultInstance() { +} #if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorResponse_File::kNameFieldNumber; const int CodeGeneratorResponse_File::kInsertionPointFieldNumber; @@ -1377,7 +1057,7 @@ const int CodeGeneratorResponse_File::kContentFieldNumber; CodeGeneratorResponse_File::CodeGeneratorResponse_File() : ::google::protobuf::Message(), _internal_metadata_(NULL) { if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse_File(); } SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File) @@ -1427,12 +1107,12 @@ void CodeGeneratorResponse_File::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_END(); } const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; } const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse_File(); return *internal_default_instance(); } @@ -1752,205 +1432,14 @@ void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) ::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const { protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// CodeGeneratorResponse_File - -// optional string name = 1; -bool CodeGeneratorResponse_File::has_name() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -void CodeGeneratorResponse_File::set_has_name() { - _has_bits_[0] |= 0x00000001u; -} -void CodeGeneratorResponse_File::clear_has_name() { - _has_bits_[0] &= ~0x00000001u; -} -void CodeGeneratorResponse_File::clear_name() { - name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_name(); -} -const ::std::string& CodeGeneratorResponse_File::name() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name) - return name_.GetNoArena(); -} -void CodeGeneratorResponse_File::set_name(const ::std::string& value) { - set_has_name(); - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name) -} -#if LANG_CXX11 -void CodeGeneratorResponse_File::set_name(::std::string&& value) { - set_has_name(); - name_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.name) -} -#endif -void CodeGeneratorResponse_File::set_name(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_name(); - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name) -} -void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { - set_has_name(); - name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name) -} -::std::string* CodeGeneratorResponse_File::mutable_name() { - set_has_name(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name) - return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* CodeGeneratorResponse_File::release_name() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name) - clear_has_name(); - return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { - if (name != NULL) { - set_has_name(); - } else { - clear_has_name(); - } - name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name) -} - -// optional string insertion_point = 2; -bool CodeGeneratorResponse_File::has_insertion_point() const { - return (_has_bits_[0] & 0x00000002u) != 0; -} -void CodeGeneratorResponse_File::set_has_insertion_point() { - _has_bits_[0] |= 0x00000002u; -} -void CodeGeneratorResponse_File::clear_has_insertion_point() { - _has_bits_[0] &= ~0x00000002u; -} -void CodeGeneratorResponse_File::clear_insertion_point() { - insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_insertion_point(); -} -const ::std::string& CodeGeneratorResponse_File::insertion_point() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) - return insertion_point_.GetNoArena(); -} -void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { - set_has_insertion_point(); - insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) -} -#if LANG_CXX11 -void CodeGeneratorResponse_File::set_insertion_point(::std::string&& value) { - set_has_insertion_point(); - insertion_point_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) -} -#endif -void CodeGeneratorResponse_File::set_insertion_point(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_insertion_point(); - insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) -} -void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { - set_has_insertion_point(); - insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) -} -::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { - set_has_insertion_point(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) - return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* CodeGeneratorResponse_File::release_insertion_point() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) - clear_has_insertion_point(); - return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { - if (insertion_point != NULL) { - set_has_insertion_point(); - } else { - clear_has_insertion_point(); - } - insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) -} - -// optional string content = 15; -bool CodeGeneratorResponse_File::has_content() const { - return (_has_bits_[0] & 0x00000004u) != 0; -} -void CodeGeneratorResponse_File::set_has_content() { - _has_bits_[0] |= 0x00000004u; -} -void CodeGeneratorResponse_File::clear_has_content() { - _has_bits_[0] &= ~0x00000004u; -} -void CodeGeneratorResponse_File::clear_content() { - content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_content(); -} -const ::std::string& CodeGeneratorResponse_File::content() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content) - return content_.GetNoArena(); -} -void CodeGeneratorResponse_File::set_content(const ::std::string& value) { - set_has_content(); - content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content) -} -#if LANG_CXX11 -void CodeGeneratorResponse_File::set_content(::std::string&& value) { - set_has_content(); - content_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.content) -} -#endif -void CodeGeneratorResponse_File::set_content(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_content(); - content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content) -} -void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { - set_has_content(); - content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content) -} -::std::string* CodeGeneratorResponse_File::mutable_content() { - set_has_content(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content) - return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* CodeGeneratorResponse_File::release_content() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content) - clear_has_content(); - return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { - if (content != NULL) { - set_has_content(); - } else { - clear_has_content(); - } - content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; } -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== +void CodeGeneratorResponse::InitAsDefaultInstance() { +} #if !defined(_MSC_VER) || _MSC_VER >= 1900 const int CodeGeneratorResponse::kErrorFieldNumber; const int CodeGeneratorResponse::kFileFieldNumber; @@ -1959,7 +1448,7 @@ const int CodeGeneratorResponse::kFileFieldNumber; CodeGeneratorResponse::CodeGeneratorResponse() : ::google::protobuf::Message(), _internal_metadata_(NULL) { if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse(); } SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse) @@ -1998,12 +1487,12 @@ void CodeGeneratorResponse::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_END(); } const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; } const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() { - protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaults(); + ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse(); return *internal_default_instance(); } @@ -2250,109 +1739,11 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { ::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const { protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::protobuf_AssignDescriptorsOnce(); - return protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// CodeGeneratorResponse - -// optional string error = 1; -bool CodeGeneratorResponse::has_error() const { - return (_has_bits_[0] & 0x00000001u) != 0; -} -void CodeGeneratorResponse::set_has_error() { - _has_bits_[0] |= 0x00000001u; -} -void CodeGeneratorResponse::clear_has_error() { - _has_bits_[0] &= ~0x00000001u; -} -void CodeGeneratorResponse::clear_error() { - error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - clear_has_error(); -} -const ::std::string& CodeGeneratorResponse::error() const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error) - return error_.GetNoArena(); -} -void CodeGeneratorResponse::set_error(const ::std::string& value) { - set_has_error(); - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error) -} -#if LANG_CXX11 -void CodeGeneratorResponse::set_error(::std::string&& value) { - set_has_error(); - error_.SetNoArena( - &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); - // @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.error) -} -#endif -void CodeGeneratorResponse::set_error(const char* value) { - GOOGLE_DCHECK(value != NULL); - set_has_error(); - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error) -} -void CodeGeneratorResponse::set_error(const char* value, size_t size) { - set_has_error(); - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast<const char*>(value), size)); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error) -} -::std::string* CodeGeneratorResponse::mutable_error() { - set_has_error(); - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error) - return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -::std::string* CodeGeneratorResponse::release_error() { - // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error) - clear_has_error(); - return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -void CodeGeneratorResponse::set_allocated_error(::std::string* error) { - if (error != NULL) { - set_has_error(); - } else { - clear_has_error(); - } - error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error) -} - -// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; -int CodeGeneratorResponse::file_size() const { - return file_.size(); -} -void CodeGeneratorResponse::clear_file() { - file_.Clear(); -} -const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { - // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_.Get(index); -} -::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { - // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_.Mutable(index); -} -::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { - // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_.Add(); -} -::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* -CodeGeneratorResponse::mutable_file() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return &file_; -} -const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; + return ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::file_level_metadata[kIndexInFileMessages]; } -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS // @@protoc_insertion_point(namespace_scope) - } // namespace compiler } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 2d66f035..0c2ad703 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -37,6 +37,33 @@ #ifdef minor #undef minor #endif + +namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto { +// Internal implementation detail -- do not use these members. +struct LIBPROTOC_EXPORT TableStruct { + static const ::google::protobuf::internal::ParseTableField entries[]; + static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; + static const ::google::protobuf::internal::ParseTable schema[4]; + static const ::google::protobuf::internal::FieldMetadata field_metadata[]; + static const ::google::protobuf::internal::SerializationTable serialization_table[]; + static const ::google::protobuf::uint32 offsets[]; +}; +void LIBPROTOC_EXPORT AddDescriptors(); +void LIBPROTOC_EXPORT InitDefaultsVersionImpl(); +void LIBPROTOC_EXPORT InitDefaultsVersion(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorRequestImpl(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorRequest(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorResponse_FileImpl(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorResponse_File(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorResponseImpl(); +void LIBPROTOC_EXPORT InitDefaultsCodeGeneratorResponse(); +inline void LIBPROTOC_EXPORT InitDefaults() { + InitDefaultsVersion(); + InitDefaultsCodeGeneratorRequest(); + InitDefaultsCodeGeneratorResponse_File(); + InitDefaultsCodeGeneratorResponse(); +} +} // namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto namespace google { namespace protobuf { namespace compiler { @@ -55,26 +82,10 @@ LIBPROTOC_EXPORT extern VersionDefaultTypeInternal _Version_default_instance_; } // namespace compiler } // namespace protobuf } // namespace google - namespace google { namespace protobuf { namespace compiler { -namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto { -// Internal implementation detail -- do not call these. -struct LIBPROTOC_EXPORT TableStruct { - static const ::google::protobuf::internal::ParseTableField entries[]; - static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; - static const ::google::protobuf::internal::ParseTable schema[]; - static const ::google::protobuf::uint32 offsets[]; - static const ::google::protobuf::internal::FieldMetadata field_metadata[]; - static const ::google::protobuf::internal::SerializationTable serialization_table[]; - static void InitDefaultsImpl(); -}; -void LIBPROTOC_EXPORT AddDescriptors(); -void LIBPROTOC_EXPORT InitDefaults(); -} // namespace protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto - // =================================================================== class LIBPROTOC_EXPORT Version : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.Version) */ { @@ -113,6 +124,7 @@ class LIBPROTOC_EXPORT Version : public ::google::protobuf::Message /* @@protoc_ static const ::google::protobuf::Descriptor* descriptor(); static const Version& default_instance(); + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY static inline const Version* internal_default_instance() { return reinterpret_cast<const Version*>( &_Version_default_instance_); @@ -219,7 +231,8 @@ class LIBPROTOC_EXPORT Version : public ::google::protobuf::Message /* @@protoc_ ::google::protobuf::int32 major_; ::google::protobuf::int32 minor_; ::google::protobuf::int32 patch_; - friend struct protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend struct ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend void ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsVersionImpl(); }; // ------------------------------------------------------------------- @@ -259,6 +272,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorRequest& default_instance(); + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY static inline const CodeGeneratorRequest* internal_default_instance() { return reinterpret_cast<const CodeGeneratorRequest*>( &_CodeGeneratorRequest_default_instance_); @@ -383,7 +397,8 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; ::google::protobuf::internal::ArenaStringPtr parameter_; ::google::protobuf::compiler::Version* compiler_version_; - friend struct protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend struct ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend void ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorRequestImpl(); }; // ------------------------------------------------------------------- @@ -423,6 +438,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse_File& default_instance(); + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY static inline const CodeGeneratorResponse_File* internal_default_instance() { return reinterpret_cast<const CodeGeneratorResponse_File*>( &_CodeGeneratorResponse_File_default_instance_); @@ -535,7 +551,8 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::internal::ArenaStringPtr insertion_point_; ::google::protobuf::internal::ArenaStringPtr content_; - friend struct protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend struct ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend void ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponse_FileImpl(); }; // ------------------------------------------------------------------- @@ -575,6 +592,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse& default_instance(); + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY static inline const CodeGeneratorResponse* internal_default_instance() { return reinterpret_cast<const CodeGeneratorResponse*>( &_CodeGeneratorResponse_default_instance_); @@ -666,14 +684,14 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; ::google::protobuf::internal::ArenaStringPtr error_; - friend struct protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend struct ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::TableStruct; + friend void ::protobuf_google_2fprotobuf_2fcompiler_2fplugin_2eproto::InitDefaultsCodeGeneratorResponseImpl(); }; // =================================================================== // =================================================================== -#if !PROTOBUF_INLINE_NOT_IN_HEADERS #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" @@ -1320,7 +1338,6 @@ CodeGeneratorResponse::file() const { #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ -#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- // ------------------------------------------------------------------- @@ -1330,7 +1347,6 @@ CodeGeneratorResponse::file() const { // @@protoc_insertion_point(namespace_scope) - } // namespace compiler } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 97769835..5ca6b4ee 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -1151,7 +1151,7 @@ void Generator::PrintFieldDescriptor( " has_default_value=$has_default_value$, default_value=$default_value$,\n" " message_type=None, enum_type=None, containing_type=None,\n" " is_extension=$is_extension$, extension_scope=None,\n" - " options=$options$$json_name$)"; + " options=$options$$json_name$, file=DESCRIPTOR)"; printer_->Print(m, field_descriptor_decl); } |