diff options
author | Feng Xiao <xfxyjwf@gmail.com> | 2015-08-22 18:25:48 -0700 |
---|---|---|
committer | Feng Xiao <xfxyjwf@gmail.com> | 2015-08-22 18:25:48 -0700 |
commit | eee38b0c018b3279f77d03dff796f440f40d3516 (patch) | |
tree | 7ff0978e30238d493fc7899b75abeb6d66939f07 /src/google/protobuf/compiler | |
parent | c3bc155aceda36ecb01cde2367a3b427f2d7ce40 (diff) | |
download | protobuf-eee38b0c018b3279f77d03dff796f440f40d3516.tar.gz protobuf-eee38b0c018b3279f77d03dff796f440f40d3516.tar.bz2 protobuf-eee38b0c018b3279f77d03dff796f440f40d3516.zip |
Down-integrate from google3.
Diffstat (limited to 'src/google/protobuf/compiler')
51 files changed, 1679 insertions, 511 deletions
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0039b00a..473eb4e6 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index e8871861..26a4f0b0 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -70,6 +70,7 @@ #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/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/stubs/map_util.h> @@ -1657,7 +1658,11 @@ bool CommandLineInterface::WriteDescriptorSet( &already_seen, file_set.mutable_file()); } } else { + set<const FileDescriptor*> already_seen; for (int i = 0; i < parsed_files.size(); i++) { + if (!already_seen.insert(parsed_files[i]).second) { + continue; + } FileDescriptorProto* file_proto = file_set.add_file(); parsed_files[i]->CopyTo(file_proto); if (source_info_in_descriptor_set_) { diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index e5b77c33..46ea5c4e 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -886,6 +886,39 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); } +TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Baz {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(3, descriptor_set.file_size()); + EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); + EXPECT_EQ("foo.proto", descriptor_set.file(1).name()); + EXPECT_EQ("baz.proto", descriptor_set.file(2).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); +} + TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 13ed0b64..c3e9fe74 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -133,8 +133,7 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { CppGenerator generator; MockGeneratorContext context; string error; - string parameter; - parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; + string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &context, &error)); parameter = "dllexport_decl=LIBPROTOC_EXPORT"; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 70d3a600..de4d7cc7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -32,7 +32,6 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <set> #include <map> #include <google/protobuf/compiler/cpp/cpp_enum.h> @@ -70,14 +69,11 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} -void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) { +void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) { if (!options_.proto_h) { return; } - map<string, string> vars; - vars["classname"] = classname_; - printer->Print(vars, "enum $classname$ : int;\n"); - printer->Print(vars, "bool $classname$_IsValid(int value);\n"); + enum_names->insert(classname_); } void EnumGenerator::GenerateDefinition(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 3e930856..f3aa72e4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -35,6 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#include <set> #include <string> #include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> @@ -60,11 +61,11 @@ class EnumGenerator { // Header stuff. - // Generate header code to forward-declare the enum. This is for use when + // Fills the name to use when declaring the enum. This is for use when // generating other .proto.h files. This code should be placed within the // enum's package namespace, but NOT within any class, even for nested // enums. - void GenerateForwardDeclaration(io::Printer* printer); + void FillForwardDeclaration(set<string>* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 965327b1..824e2205 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -35,7 +35,6 @@ #include <google/protobuf/compiler/cpp/cpp_enum_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> namespace google { diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 43df1d88..8d47d4e0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -47,6 +47,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 1f0a8205..5dae4cdd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_file.h> +#include <map> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> @@ -93,22 +94,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateHeader(io::Printer* printer) { - GenerateTopHeaderGuard(printer); +void FileGenerator::GenerateProtoHeader(io::Printer* printer) { + if (!options_.proto_h) { + return; + } + + string filename_identifier = FilenameIdentifier(file_->name()); + GenerateTopHeaderGuard(printer, filename_identifier); + GenerateLibraryIncludes(printer); - GenerateDependencyIncludes(printer); + + for (int i = 0; i < file_->public_dependency_count(); i++) { + const FileDescriptor* dep = file_->public_dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\" // IWYU pragma: export\n", + "dependency", dependency); + } printer->Print( "// @@protoc_insertion_point(includes)\n"); + GenerateForwardDeclarations(printer); // Open namespace. GenerateNamespaceOpeners(printer); GenerateGlobalStateFunctionDeclarations(printer); - GenerateMessageForwardDeclarations(printer); printer->Print("\n"); @@ -133,6 +148,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { GenerateInlineFunctionDefinitions(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -144,19 +164,89 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n" "\n"); - GenerateBottomHeaderGuard(printer); + GenerateBottomHeaderGuard(printer, filename_identifier); +} + +void FileGenerator::GeneratePBHeader(io::Printer* printer) { + string filename_identifier = + FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); + GenerateTopHeaderGuard(printer, filename_identifier); + + if (options_.proto_h) { + printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", + "basename", StripProto(file_->name())); + } else { + GenerateLibraryIncludes(printer); + } + GenerateDependencyIncludes(printer); + + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + + + + // Open namespace. + GenerateNamespaceOpeners(printer); + + if (!options_.proto_h) { + GenerateGlobalStateFunctionDeclarations(printer); + GenerateMessageForwardDeclarations(printer); + + printer->Print("\n"); + + GenerateEnumDefinitions(printer); + + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateMessageDefinitions(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateServiceDefinitions(printer); + + GenerateExtensionIdentifiers(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateInlineFunctionDefinitions(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + + // Close up namespace. + GenerateNamespaceClosers(printer); + + if (!options_.proto_h) { + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + + GenerateBottomHeaderGuard(printer, filename_identifier); } void FileGenerator::GenerateSource(io::Printer* printer) { + string header = + StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// 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 \"$basename$.pb.h\"\n" + "#include \"$header$\"\n" "\n" "#include <algorithm>\n" // for swap() "\n" @@ -165,7 +255,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), - "basename", StripProto(file_->name())); + "header", header); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { @@ -181,6 +271,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/wire_format.h>\n"); } + if (options_.proto_h) { + // Use the smaller .proto.h files. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dep = file_->dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\"\n", + "dependency", dependency); + } + } + printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -276,6 +378,59 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n"); } +class FileGenerator::ForwardDeclarations { + public: + ~ForwardDeclarations() { + for (map<string, ForwardDeclarations *>::iterator it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + delete it->second; + } + namespaces_.clear(); + } + + ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { + ForwardDeclarations*& ns = namespaces_[ns_name]; + if (ns == NULL) { + ns = new ForwardDeclarations; + } + return ns; + } + + set<string>& classes() { return classes_; } + set<string>& enums() { return enums_; } + + void Print(io::Printer* printer) const { + for (set<string>::const_iterator it = enums_.begin(), end = enums_.end(); + it != end; ++it) { + printer->Print("enum $enumname$ : int;\n" + "bool $enumname$_IsValid(int value);\n", + "enumname", it->c_str()); + } + for (set<string>::const_iterator it = classes_.begin(), + end = classes_.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); + } + for (map<string, ForwardDeclarations *>::const_iterator + it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + printer->Print("namespace $nsname$ {\n", + "nsname", it->first); + it->second->Print(printer); + printer->Print("} // namespace $nsname$\n", + "nsname", it->first); + } + } + + + private: + map<string, ForwardDeclarations*> namespaces_; + set<string> classes_; + set<string> enums_; +}; + void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for @@ -434,12 +589,17 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); +#ifdef _MSC_VER + bool breakdown_large_file = true; +#else + bool breakdown_large_file = false; +#endif // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 // bytes in length". Declare a static array of characters rather than use a // string literal. - if (file_data.size() > 65535) { + if (breakdown_large_file && file_data.size() > 65535) { printer->Print( - "static const char descriptor[] = {\n"); + "static const char descriptor[] = {\n"); printer->Indent(); // Only write 25 bytes per line. @@ -447,26 +607,25 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_data.size();) { for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { printer->Print( - "$char$, ", - "char", SimpleItoa(file_data[i])); + "$char$, ", + "char", SimpleItoa(file_data[i])); } printer->Print( - "\n"); + "\n"); } printer->Outdent(); printer->Print( - "};\n"); + "};\n"); printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", - "size", SimpleItoa(file_data.size())); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", + "size", SimpleItoa(file_data.size())); } else { - printer->Print( "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); - + // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { @@ -474,11 +633,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", EscapeTrigraphs( CEscape(file_data.substr(i, kBytesPerLine)))); - } - printer->Print( - ", $size$);\n", + } + printer->Print( + ", $size$);\n", "size", SimpleItoa(file_data.size())); - } // Call MessageFactory::InternalRegisterGeneratedFile(). @@ -548,8 +706,40 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { } } -void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { + ForwardDeclarations decls; + for (int i = 0; i < file_->dependency_count(); i++) { + FileGenerator dependency(file_->dependency(i), options_); + dependency.FillForwardDeclarations(&decls); + } + FillForwardDeclarations(&decls); + decls.Print(printer); +} + +void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { + for (int i = 0; i < file_->public_dependency_count(); i++) { + FileGenerator dependency(file_->public_dependency(i), options_); + dependency.FillForwardDeclarations(decls); + } + for (int i = 0; i < package_parts_.size(); i++) { + decls = decls->AddOrGetNamespace(package_parts_[i]); + } + // Generate enum definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillEnumForwardDeclarations(&decls->enums()); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->FillForwardDeclaration(&decls->enums()); + } + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillMessageForwardDeclarations( + &decls->classes()); + } +} + +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" @@ -564,8 +754,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { "filename_identifier", filename_identifier); } -void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateBottomHeaderGuard( + io::Printer* printer, const string& filename_identifier) { printer->Print( "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", "filename_identifier", filename_identifier); @@ -696,9 +886,13 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( } void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - // Generate forward declarations of classes. + set<string> classes; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateMessageForwardDeclaration(printer); + message_generators_[i]->FillMessageForwardDeclarations(&classes); + } + for (set<string>::const_iterator it = classes.begin(), end = classes.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); } } @@ -804,10 +998,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { // Methods of the dependent base class must always be inline in the header. message_generators_[i]->GenerateDependentInlineMethods(printer); } - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); } void FileGenerator::GenerateProto2NamespaceEnumSpecializations( diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index e68f67bb..29cdaea5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -69,10 +69,14 @@ class FileGenerator { const Options& options); ~FileGenerator(); - void GenerateHeader(io::Printer* printer); + void GenerateProtoHeader(io::Printer* printer); + void GeneratePBHeader(io::Printer* printer); void GenerateSource(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); @@ -80,9 +84,19 @@ class FileGenerator { void GenerateNamespaceOpeners(io::Printer* printer); void GenerateNamespaceClosers(io::Printer* printer); + // For other imports, generates their forward-declarations. + void GenerateForwardDeclarations(io::Printer* printer); + + // Internal helper used by GenerateForwardDeclarations: fills 'decls' + // with all necessary forward-declarations for this file and its + // transient depednencies. + void FillForwardDeclarations(ForwardDeclarations* decls); + // Generates top or bottom of a header file. - void GenerateTopHeaderGuard(io::Printer* printer); - void GenerateBottomHeaderGuard(io::Printer* printer); + void GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier); + void GenerateBottomHeaderGuard(io::Printer* printer, + const string& filename_identifier); // Generates #include directives. void GenerateLibraryIncludes(io::Printer* printer); @@ -92,10 +106,20 @@ class FileGenerator { void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); // Generates types for classes. - void GenerateMessageForwardDeclarations(io::Printer* printer); void GenerateMessageDefinitions(io::Printer* printer); + // Generates forward-declarations for just this file's classes. This is + // used for .pb.h headers, but not in proto_h mode. + void GenerateMessageForwardDeclarations(io::Printer* printer); + + // Fills in types for forward declarations. This is used internally, and + // also by other FileGenerators to determine imports' declarations. + void FillMessageForwardDeclarations(ForwardDeclarations* decls); + void FillMessageDefinitions(ForwardDeclarations* decls); + // Generates enum definitions. + void GenerateEnumForwardDeclarations(io::Printer* printer); + void FillEnumForwardDeclarations(ForwardDeclarations* decls); void GenerateEnumDefinitions(io::Printer* printer); // Generates generic service definitions. diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 99416372..781526b5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -100,16 +100,23 @@ bool CppGenerator::Generate(const FileDescriptor* file, string basename = StripProto(file->name()); - basename.append(".pb"); FileGenerator file_generator(file, file_options); - // Generate header. + // Generate header(s). + if (file_options.proto_h) { + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".proto.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateProtoHeader(&printer); + } + + basename.append(".pb"); { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".h")); io::Printer printer(output.get(), '$'); - file_generator.GenerateHeader(&printer); + file_generator.GeneratePBHeader(&printer); } // Generate cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 0f3688d0..678a995a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -39,6 +39,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -68,7 +69,7 @@ const char* const kKeywordList[] = { "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", + "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", @@ -174,6 +175,14 @@ string SuperClassName(const Descriptor* descriptor) { "::google::protobuf::Message" : "::google::protobuf::MessageLite"; } +string DependentBaseDownCast() { + return "reinterpret_cast<T*>(this)->"; +} + +string DependentBaseConstDownCast() { + return "reinterpret_cast<const T*>(this)->"; +} + string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -208,6 +217,19 @@ string FieldConstantName(const FieldDescriptor *field) { } bool IsFieldDependent(const FieldDescriptor* field) { + if (field->containing_oneof() != NULL && + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + return true; + } + if (field->is_map()) { + const Descriptor* map_descriptor = field->message_type(); + for (int i = 0; i < map_descriptor->field_count(); i++) { + if (IsFieldDependent(map_descriptor->field(i))) { + return true; + } + } + return false; + } if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { return false; } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 4bbf8303..29c1f90b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -70,8 +70,15 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); // This is a class name, like "ProtoName_InternalBase". string DependentBaseClassTemplateName(const Descriptor* descriptor); +// Name of the base class: either the dependent base class (for use with +// proto_h) or google::protobuf::Message. string SuperClassName(const Descriptor* descriptor); +// Returns a string that down-casts from the dependent base class to the +// derived class. +string DependentBaseDownCast(); +string DependentBaseConstDownCast(); + // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0ff0d27c..a14d8986 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -100,8 +100,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MapFieldGenerator:: MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { + const Options& options) + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -152,7 +153,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MapFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void MapFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index d27d4851..5e205623 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -63,6 +63,7 @@ class MapFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; + const bool dependent_field_; map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index b0e38755..aa10b0bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -39,7 +39,6 @@ #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif -#include <set> #include <utility> #include <vector> #include <google/protobuf/compiler/cpp/cpp_message.h> @@ -415,31 +414,34 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, use_dependent_base_ = true; } } + if (options.proto_h && descriptor->oneof_decl_count() > 0) { + // Always make oneofs dependent. + use_dependent_base_ = true; + } } MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -GenerateMessageForwardDeclaration(io::Printer* printer) { - printer->Print("class $classname$;\n", - "classname", classname_); +FillMessageForwardDeclarations(set<string>* class_names) { + class_names->insert(classname_); for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need forward declaration. Since map entry // message cannot be a top level class, we just need to avoid calling // GenerateForwardDeclaration here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateMessageForwardDeclaration(printer); + nested_generators_[i]->FillMessageForwardDeclarations(class_names); } } void MessageGenerator:: -GenerateEnumForwardDeclaration(io::Printer* printer) { +FillEnumForwardDeclarations(set<string>* enum_names) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateEnumForwardDeclaration(printer); + nested_generators_[i]->FillEnumForwardDeclarations(enum_names); } for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateForwardDeclaration(printer); + enum_generators_[i]->FillForwardDeclaration(enum_names); } } @@ -484,13 +486,6 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); printer->Print("\n"); } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - PrintFieldComment(printer, oneof); - printer->Print( - "void clear_$oneof_name$();\n", - "oneof_name", oneof->name()); - } } void MessageGenerator:: @@ -505,7 +500,9 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { vars["constant_name"] = FieldConstantName(field); bool dependent_field = use_dependent_base_ && IsFieldDependent(field); - if (dependent_field) { + if (dependent_field && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_map()) { // If this field is dependent, the dependent base class determines // the message type from the derived class (which is a template // parameter). This typedef is for that: @@ -594,8 +591,8 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { vars["tmpl"] = "template<class T>\n"; vars["dependent_classname"] = DependentBaseClassTemplateName(descriptor_) + "<T>"; - vars["this_message"] = "reinterpret_cast<T*>(this)->"; - vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + vars["this_message"] = DependentBaseDownCast(); + vars["this_const_message"] = DependentBaseConstDownCast(); GenerateFieldClear(field, vars, printer); } @@ -721,13 +718,15 @@ GenerateFieldClear(const FieldDescriptor* field, printer->Print(vars, "if ($this_message$has_$name$()) {\n"); printer->Indent(); - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); printer->Print(vars, "$this_message$clear_has_$oneof_name$();\n"); printer->Outdent(); printer->Print("}\n"); } else { - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); if (HasFieldPresence(descriptor_->file())) { if (!field->is_repeated()) { printer->Print(vars, @@ -752,6 +751,18 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); vars["inline"] = is_inline ? "inline " : ""; + if (use_dependent_base_ && IsFieldDependent(field)) { + vars["tmpl"] = "template<class T>\n"; + vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + "<T>"; + vars["this_message"] = "reinterpret_cast<T*>(this)->"; + vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + } else { + vars["tmpl"] = ""; + vars["dependent_classname"] = vars["classname"]; + vars["this_message"] = ""; + vars["this_const_message"] = ""; + } // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -775,10 +786,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { } if (!use_dependent_base_ || !IsFieldDependent(field)) { - vars["tmpl"] = ""; - vars["dependent_classname"] = vars["classname"]; - vars["this_message"] = ""; - vars["this_const_message"] = ""; GenerateFieldClear(field, vars, printer); } @@ -915,15 +922,32 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "\n"); } else { - printer->Print( - "inline const ::std::string& unknown_fields() const {\n" - " return _unknown_fields_;\n" - "}\n" - "\n" - "inline ::std::string* mutable_unknown_fields() {\n" - " return &_unknown_fields_;\n" - "}\n" - "\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.Get(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.Mutable(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n" + "}\n" + "\n"); + } else { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.GetNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.MutableNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n"); + } } } @@ -1068,6 +1092,10 @@ GenerateClassDefinition(io::Printer* printer) { } } uses_string_ = false; + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + uses_string_ = true; + } for (int i = 0; i < descriptors.size(); i++) { const FieldDescriptor* field = descriptors[i]; if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { @@ -1201,18 +1229,11 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - if (use_dependent_base_) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } else { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "void clear_$oneof_name$();\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); } if (HasGeneratedMethods(descriptor_->file()) && @@ -1262,7 +1283,7 @@ GenerateClassDefinition(io::Printer* printer) { "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { printer->Print( - "::std::string _unknown_fields_;\n" + "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n" "::google::protobuf::Arena* _arena_ptr_;\n" "\n"); } @@ -1919,6 +1940,13 @@ GenerateSharedConstructorCode(io::Printer* printer) { uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", "_cached_size_ = 0;\n").c_str()); + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "_unknown_fields_.UnsafeSetDefault(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { field_generators_.get(descriptor_->field(i)) @@ -1955,6 +1983,22 @@ GenerateSharedDestructorCode(io::Printer* printer) { "}\n" "\n"); } + + // Write the desctructor for _unknown_fields_ in lite runtime. + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.Destroy(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.DestroyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + } + // Write the destructors for each field except oneof members. for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { @@ -2463,8 +2507,16 @@ GenerateClear(io::Printer* printer) { " mutable_unknown_fields()->Clear();\n" "}\n"); } else { - printer->Print( - "mutable_unknown_fields()->clear();\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.ClearToEmpty(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.ClearToEmptyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } } } @@ -2481,33 +2533,22 @@ GenerateOneofClear(io::Printer* printer) { oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); string message_class; - if (use_dependent_base_) { - oneof_vars["tmpl"] = "template<class T>\n"; - oneof_vars["inline"] = "inline "; - oneof_vars["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_) + "<T>"; - oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->"; - message_class = "T::"; - } else { - oneof_vars["tmpl"] = ""; - oneof_vars["inline"] = ""; - oneof_vars["dependent_classname"] = classname_; - oneof_vars["this_message"] = ""; - } - printer->Print(oneof_vars, - "$tmpl$" - "$inline$" - "void $dependent_classname$::clear_$oneofname$() {\n"); + "void $classname$::clear_$oneofname$() {\n"); printer->Indent(); + // In .proto.h mode, fields with a dependent type will generate + // clearing code that down casts from the dependent base class. + // However, clear_oneof() methods are always in the .cc file, and thus + // must remain in the derived base. So, to make the clearing code work, + // we add a typedef so that the down cast works (it will be a no-op). printer->Print(oneof_vars, - "switch($this_message$$oneofname$_case()) {\n"); + "typedef $classname$ T;\n" + "switch($oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "case $message_class$k$field_name$: {\n", - "message_class", message_class, + "case k$field_name$: {\n", "field_name", UnderscoresToCamelCase(field->name(), true)); printer->Indent(); // We clear only allocated objects in oneofs @@ -2524,20 +2565,16 @@ GenerateOneofClear(io::Printer* printer) { "}\n"); } printer->Print( - "case $message_class$$cap_oneof_name$_NOT_SET: {\n" + "case $cap_oneof_name$_NOT_SET: {\n" " break;\n" "}\n", - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n" - "$this_message$_oneof_case_[$oneof_index$] = " - "$message_class$$cap_oneof_name$_NOT_SET;\n", - "this_message", oneof_vars["this_message"], + "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", "oneof_index", SimpleItoa(i), - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); @@ -2612,7 +2649,7 @@ GenerateSwap(io::Printer* printer) { printer->Print( "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); } else { - printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n"); + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } } else { // Still swap internal_metadata as it may contain more than just diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 23dad10c..8e19a3f0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -39,8 +39,8 @@ #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <set> #include <string> -#include <vector> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_options.h> @@ -66,9 +66,10 @@ class MessageGenerator { // Header stuff. - // Generate foward declarations for this class and all its nested types. - void GenerateMessageForwardDeclaration(io::Printer* printer); - void GenerateEnumForwardDeclaration(io::Printer* printer); + // Return names for foward declarations of this class and all its nested + // types. + void FillMessageForwardDeclarations(set<string>* class_names); + void FillEnumForwardDeclarations(set<string>* enum_names); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index ba318d10..b4545892 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -63,6 +63,14 @@ void SetMessageVariables(const FieldDescriptor* descriptor, SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); + if (options.proto_h && IsFieldDependent(descriptor)) { + (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor); + (*variables)["dependent_typename"] = + "typename T::" + DependentTypeName(descriptor); + } else { + (*variables)["dependent_type"] = FieldMessageTypeName(descriptor); + (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor); + } } } // namespace @@ -85,7 +93,21 @@ GeneratePrivateMembers(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + +void MessageFieldGenerator:: GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + // Arena manipulation code is out-of-line in the derived message class. + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); } void MessageFieldGenerator:: @@ -103,11 +125,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$type$* _slow_$release_name$()$deprecation$;\n" "public:\n"); } - printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n" - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + GenerateGetterDeclaration(printer); + if (!dependent_field_) { + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + } if (SupportsArenas(descriptor_)) { printer->Print(variables_, "$type$* unsafe_arena_release_$name$()$deprecation$;\n" @@ -123,12 +147,12 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( "void $classname$::_slow_mutable_$name$() {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); } else { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); } printer->Print(variables_, "}\n" @@ -151,7 +175,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( if (SupportsArenas(descriptor_->message_type())) { // NOTE: the same logic is mirrored in weak_message_field.cc. Any // arena-related semantics changes should be made in both places. - printer->Print(variables_, + printer->Print(variables_, "void $classname$::_slow_set_allocated_$name$(\n" " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n" " if (message_arena != NULL && \n" @@ -189,15 +213,139 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( void MessageFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + + map<string, string> variables(variables_); + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = DependentBaseDownCast(); + if (!variables["set_hasbit"].empty()) { + variables["set_hasbit"] = + variables["this_message"] + variables["set_hasbit"]; + } + if (!variables["clear_hasbit"].empty()) { + variables["clear_hasbit"] = + variables["this_message"] + variables["clear_hasbit"]; + } + + if (SupportsArenas(descriptor_)) { + printer->Print(variables, + "template <class T>\n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if ($name$_ == NULL) {\n" + " $this_message$_slow_mutable_$name$();\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $clear_hasbit$\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " return $this_message$_slow_$release_name$();\n" + " } else {\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + "}\n" + "template <class T>\n" + "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" + " if (message_arena == NULL) {\n" + " delete $name$_;\n" + " }\n" + " if ($name$ != NULL) {\n"); + if (SupportsArenas(descriptor_->message_type())) { + // If we're on an arena and the incoming message is not, simply Own() it + // rather than copy to the arena -- either way we need a heap dealloc, + // so we might as well defer it. Otherwise, if incoming message is on a + // different ownership domain (specific arena, or the heap) than we are, + // copy to our arena (or heap, as the case may be). + printer->Print(variables, + " $this_message$_slow_set_allocated_$name$(message_arena, " + "&$name$);\n"); + } else { + printer->Print(variables, + " if (message_arena != NULL) {\n" + " message_arena->Own($name$);\n" + " }\n"); + } + printer->Print(variables, + " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + // TODO(dlj): move insertion points to message class. + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\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" + " if ($name$_ == NULL) {\n" + " $name$_ = new $dependent_typename$;\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n" + "template <class T>\n" + "inline void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " delete $name$_;\n"); + + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables, + " if ($name$ != NULL && static_cast< $dependent_typename$* >($name$)" + "->GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } + + printer->Print(variables, + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } } void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" + "$inline$const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( @@ -206,19 +354,25 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", // Without. " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); + printer->Print(variables, "}\n"); + + if (dependent_field_) { + return; + } if (SupportsArenas(descriptor_)) { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" - " _slow_mutable_$name$();" + " _slow_mutable_$name$();\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" @@ -228,7 +382,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return temp;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ " + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n" " if (message_arena == NULL) {\n" " delete $name$_;\n" @@ -260,8 +415,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " $name$_ = new $type$;\n" @@ -269,13 +424,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$" + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " delete $name$_;\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -301,15 +458,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n" - "$name$_ = NULL;\n"); + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL && " + "$this_message$$name$_ != NULL) delete $this_message$$name$_;\n" + "$this_message$$name$_ = NULL;\n"); } else { - printer->Print(variables_, - "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); + printer->Print(variables, + "if ($this_message$$name$_ != NULL) $this_message$$name$_->" + "$dependent_type$::Clear();\n"); } } @@ -370,79 +531,149 @@ GenerateByteSize(io::Printer* printer) const { MessageOneofFieldGenerator:: MessageOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : MessageFieldGenerator(descriptor, options) { + : MessageFieldGenerator(descriptor, options), + dependent_base_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} + +void MessageOneofFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Otherwise, the logic is the same as MessageFields. + if (!dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); + MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer); +} + +void MessageOneofFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Unlike MessageField, this means there is no (non-dependent) getter to + // generate. + if (dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + void MessageOneofFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + if (!dependent_base_) { + return; + } + map<string, string> variables(variables_); + variables["inline"] = "inline "; + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = "reinterpret_cast<T*>(this)->"; + // Const message access is needed for the dependent getter. + variables["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + variables["tmpl"] = "template <class T>\n"; + variables["field_member"] = variables["this_message"] + + variables["oneof_prefix"] + variables["name"] + + "_"; + InternalGenerateInlineAccessorDefinitions(variables, printer); } void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + if (dependent_base_) { + return; + } map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; + variables["dependent_classname"] = variables["classname"]; + variables["this_message"] = ""; + variables["this_const_message"] = ""; + variables["tmpl"] = ""; + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + variables["dependent_type"] = variables["type"]; + InternalGenerateInlineAccessorDefinitions(variables, printer); +} + +void MessageOneofFieldGenerator:: +GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + + //printer->Print(variables, +} + +void MessageOneofFieldGenerator:: +InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, + io::Printer* printer) const { + printer->Print(variables, + "$tmpl$" + "$inline$ " + "const $type$& $dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$has_$name$()\n" + " ? *$this_const_message$$oneof_prefix$$name$_\n" + " : $dependent_type$::default_instance();\n" + "}\n"); + if (SupportsArenas(descriptor_)) { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n"); + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $field_member$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } else { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $this_message$$oneof_prefix$$name$_ = \n" + " ::google::protobuf::Arena::Create< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " if (GetArenaNoVirtual() != NULL) {\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" // N.B.: safe to use the underlying field pointer here because we are sure // that it is non-NULL (because has_$name$() returned true). - " $type$* temp = new $type$;\n" - " temp->MergeFrom(*$oneof_prefix$$name$_);\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = new $dependent_typename$;\n" + " temp->MergeFrom(*$field_member$);\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " }\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" - " return temp;\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -450,32 +681,42 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, // If incoming message is on the heap and we are on an arena, just Own() // it (see above). If it's on a different arena than we are or one of us // is on the heap, we make a copy to our arena/heap. - " if (GetArenaNoVirtual() != NULL &&\n" + " if ($this_message$GetArenaNoVirtual() != NULL &&\n" " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" - " } else if (GetArenaNoVirtual() !=\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" + " } else if ($this_message$GetArenaNoVirtual() !=\n" " ::google::protobuf::Arena::GetArena($name$)) {\n" - " $type$* new_$name$ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n" + " $dependent_typename$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } else { printer->Print(variables, - " if (GetArenaNoVirtual() != NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" - "$type$* $name$) {\n" + "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $oneof_prefix$$name$_;\n" + " $oneof_prefix$$name$_ = NULL;\n" + " return temp;\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$" + "($type$* $name$) {\n" // We rely on the oneof clear method to free the earlier contents of this // oneof. We can directly use the pointer we're given to set the new // value. @@ -489,44 +730,47 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new $type$;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = new $dependent_typename$;\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " if ($name$->GetArena() != NULL) {\n" - " $type$* new_$name$ = new $type$;\n" + " if (static_cast< $dependent_typename$*>($name$)->" + "GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -535,14 +779,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL) {\n" - " delete $oneof_prefix$$name$_;\n" + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL) {\n" + " delete $this_message$$oneof_prefix$$name$_;\n" "}\n"); } else { - printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + printer->Print(variables, + "delete $this_message$$oneof_prefix$$name$_;\n"); } } @@ -562,7 +808,9 @@ GenerateConstructorCode(io::Printer* printer) const { RepeatedMessageFieldGenerator:: RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + dependent_getter_(dependent_field_ && options.safe_boundary_check) { SetMessageVariables(descriptor, &variables_, options); } @@ -575,60 +823,160 @@ GeneratePrivateMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -GenerateDependentAccessorDeclarations(io::Printer* printer) const { -} - -void RepeatedMessageFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { +InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n" "$type$* mutable_$name$(int index)$deprecation$;\n" "$type$* add_$name$()$deprecation$;\n"); + if (dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n" "::google::protobuf::RepeatedPtrField< $type$ >*\n" " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } } void RepeatedMessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer, - bool is_inline) const { +GenerateAccessorDeclarations(io::Printer* printer) const { + if (!dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (!dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } + if (!dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = DependentBaseDownCast(); + variables["this_const_message"] = DependentBaseConstDownCast(); + + if (dependent_getter_) { + printer->Print(variables, + "template <class T>\n" + "inline const $type$& $dependent_classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$$name$_.$cppget$(index);\n" + "}\n"); + } + + // Generate per-element accessors: printer->Print(variables, - "$inline$ const $type$& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.$cppget$(index);\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$(int index) {\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" + " return $this_message$$name$_.Mutable(index);\n" "}\n" - "$inline$ $type$* $classname$::add_$name$() {\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::add_$name$() {\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $name$_.Add();\n" + " return $this_message$$name$_.Add();\n" "}\n"); + + + if (dependent_getter_) { + printer->Print(variables, + "template <class T>\n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $this_const_message$$name$_;\n" + "}\n"); + } + + // Generate mutable access to the entire list: printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" + "template <class T>\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$dependent_classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" + " return &$this_message$$name$_;\n" "}\n"); } void RepeatedMessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline " : ""; + + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.$cppget$(index);\n" + "}\n"); + } + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "$type$* $classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable(index);\n" + "}\n" + "$inline$" + "$type$* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + " return $name$_.Add();\n" + "}\n"); + } + + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); + } + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void RepeatedMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 9ddf9643..35efd0fa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -68,6 +68,11 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; protected: + void GenerateArenaManipulationCode(const map<string, string>& variables, + io::Printer* printer) const; + + virtual void GenerateGetterDeclaration(io::Printer* printer) const; + const FieldDescriptor* descriptor_; const bool dependent_field_; map<string, string> variables_; @@ -83,15 +88,23 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {} + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + protected: + void GenerateGetterDeclaration(io::Printer* printer) const; + private: + void InternalGenerateInlineAccessorDefinitions( + const map<string, string>& variables, io::Printer* printer) const; + + const bool dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); }; @@ -118,7 +131,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: + void InternalGenerateTypeDependentAccessorDeclarations( + io::Printer* printer) const; + const FieldDescriptor* descriptor_; + const bool dependent_field_; + const bool dependent_getter_; map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 1a3896a1..d1af6dda 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -421,7 +421,8 @@ GenerateByteSize(io::Printer* printer) const { StringOneofFieldGenerator:: StringOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : StringFieldGenerator(descriptor, options) { + : StringFieldGenerator(descriptor, options), + dependent_field_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -604,13 +605,29 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + if (dependent_field_) { + variables["this_message"] = DependentBaseDownCast(); + // This clearing code may be in the dependent base class. If the default + // value is an empty string, then the $default_variable$ is a global + // singleton. If the default is not empty, we need to down-cast to get the + // default value's global singleton instance. See SetStringVariables() for + // possible values of default_variable. + if (!descriptor_->default_value_string().empty()) { + variables["default_variable"] = + DependentBaseDownCast() + variables["default_variable"]; + } + } else { + variables["this_message"] = ""; + } if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "$oneof_prefix$$name$_.Destroy($default_variable$,\n" - " GetArenaNoVirtual());\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_.Destroy($default_variable$,\n" + " $this_message$GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_." + "DestroyNoArena($default_variable$);\n"); } } @@ -664,7 +681,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { RepeatedStringFieldGenerator:: RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index d1f19cd9..616e2067 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -93,6 +93,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateMergeFromCodedStream(io::Printer* printer) const; private: + const bool dependent_field_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index bd1c0fde..e5ef6ecd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -67,7 +67,9 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/dynamic_message.h> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 43eb0ed5..33c9328f 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -44,6 +44,7 @@ #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/map_util.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 0353b607..8a09f3a8 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -181,8 +181,8 @@ void EnumGenerator::Generate(io::Printer* printer) { " internalGetValueMap() {\n" " return internalValueMap;\n" "}\n" - "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" - " internalValueMap =\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" " return $classname$.valueOf(number);\n" diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 39318a19..558da968 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 697a07a7..2c3608c2 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index e69de29b..62186386 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -0,0 +1,226 @@ +// 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: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_enum_lite.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool EnumHasCustomOptions(const EnumDescriptor* descriptor) { + if (descriptor->options().unknown_fields().field_count() > 0) return true; + for (int i = 0; i < descriptor->value_count(); ++i) { + const EnumValueDescriptor* value = descriptor->value(i); + if (value->options().unknown_fields().field_count() > 0) return true; + } + return false; +} +} // namespace + +EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context) + : descriptor_(descriptor), immutable_api_(immutable_api), + name_resolver_(context->GetNameResolver()) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumLiteGenerator::~EnumLiteGenerator() {} + +void EnumLiteGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.Internal.EnumLite {\n", + "classname", descriptor_->name()); + } + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + map<string, string> vars; + vars["name"] = canonical_values_[i]->name(); + vars["index"] = SimpleItoa(canonical_values_[i]->index()); + vars["number"] = SimpleItoa(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } + printer->Print(vars, + "$name$($index$, $number$),\n"); + } + + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } + + printer->Print( + ";\n" + "\n"); + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + map<string, string> vars; + vars["classname"] = descriptor_->name(); + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); + printer->Print(vars, + "public static final $classname$ $name$ = $canonical_name$;\n"); + } + + for (int i = 0; i < descriptor_->value_count(); i++) { + map<string, string> vars; + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = SimpleItoa(descriptor_->value(i)->number()); + WriteEnumValueDocComment(printer, descriptor_->value(i)); + printer->Print(vars, + "public static final int $name$_VALUE = $number$;\n"); + } + printer->Print("\n"); + + // ----------------------------------------------------------------- + + printer->Print( + "\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + printer->Print( + " return value;\n" + "}\n" + "\n" + "public static $classname$ valueOf(int value) {\n" + " switch (value) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print( + "case $number$: return $name$;\n", + "name", canonical_values_[i]->name(), + "number", SimpleItoa(canonical_values_[i]->number())); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " default: return null;\n" + " }\n" + "}\n" + "\n" + "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" + " internalGetValueMap() {\n" + " return internalValueMap;\n" + "}\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" + " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" + " public $classname$ findValueByNumber(int number) {\n" + " return $classname$.valueOf(number);\n" + " }\n" + " };\n" + "\n", + "classname", descriptor_->name()); + + printer->Print( + "private final int value;\n\n" + "private $classname$(int index, int value) {\n", + "classname", descriptor_->name()); + printer->Print( + " this.value = value;\n" + "}\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +bool EnumLiteGenerator::CanUseEnumValues() { + if (canonical_values_.size() != descriptor_->value_count()) { + return false; + } + for (int i = 0; i < descriptor_->value_count(); i++) { + if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { + return false; + } + } + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h index e69de29b..ee2f5f7a 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.h +++ b/src/google/protobuf/compiler/java/java_enum_lite.h @@ -0,0 +1,99 @@ +// 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: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ + +#include <string> +#include <vector> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class EnumLiteGenerator { + public: + explicit EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context); + ~EnumLiteGenerator(); + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same numeric + // value. Java, however, does not allow multiple enum constants to be + // considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector<Alias> aliases_; + + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + + bool CanUseEnumValues(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index 3f0fa11f..c5434767 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -39,6 +39,7 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum_field.h> diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 00f3c601..0e24da24 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -44,6 +44,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/logging.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 96d2545f..99ba6a18 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -332,6 +332,10 @@ inline bool PreserveUnknownFields(const Descriptor* descriptor) { return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } +inline bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->full_name() == "google.protobuf.Any"; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 44b86cd7..3e035c89 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -314,6 +314,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " internalGetMutable$capitalized_name$().getMutableMap(),\n" " $name$ValueConverter);\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -331,6 +339,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$Value() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -346,6 +362,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index cd1698f0..4fe656d3 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -303,6 +303,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -321,6 +329,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$Value();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -337,6 +353,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 09b0fd94..80d6e9ad 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -255,6 +255,18 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName( + descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -292,8 +304,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { " com.google.protobuf.GeneratedMessage implements\n" " $extra_interfaces$\n" " $classname$OrBuilder {\n"); - - builder_type = "com.google.protobuf.GeneratedMessage.Builder"; + builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>"; } printer->Indent(); // Using builder_type, instead of Builder, prevents the Builder class from @@ -435,6 +446,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "\n"); } + if (IsAnyMessage(descriptor_)) { + GenerateAnyMethods(printer); + } + // Fields for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("public static final int $constant_name$ = $number$;\n", @@ -578,9 +593,8 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Print( "}\n" "\n" - "private int memoizedSerializedSize = -1;\n" "public int getSerializedSize() {\n" - " int size = memoizedSerializedSize;\n" + " int size = memoizedSize;\n" " if (size != -1) return size;\n" "\n" " size = 0;\n"); @@ -612,7 +626,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Outdent(); printer->Print( - " memoizedSerializedSize = size;\n" + " memoizedSize = size;\n" " return size;\n" "}\n" "\n"); @@ -948,22 +962,58 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("boolean result = true;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "result = result && (has$name$() == other.has$name$());\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print( + "}\n"); + } + } + } + + // Compare oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "result = result && get$oneof_capitalized_name$Case().equals(\n" + " other.get$oneof_capitalized_name$Case());\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Print( + "if (!result) return false;\n" + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { + field_generators_.get(field).GenerateEqualsCode(printer); + printer->Print("break;\n"); printer->Outdent(); - printer->Print( - "}\n"); } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); } + if (PreserveUnknownFields(descriptor_)) { // Always consider unknown fields for equality. This will sometimes return // false for non-canonical ordering when running in LITE_RUNTIME but it's @@ -1198,7 +1248,7 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" + "private static final com.google.protobuf.Parser<$classname$> PARSER =\n" " new com.google.protobuf.AbstractParser<$classname$>() {\n", "classname", descriptor_->name()); printer->Indent(); @@ -1250,6 +1300,10 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { "\n"); printer->Print( + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return PARSER;\n" + "}\n" + "\n" "@java.lang.Override\n" "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" " return PARSER;\n" @@ -1269,6 +1323,50 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { } +void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { + printer->Print( + "private static String getTypeUrl(\n" + " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" + " return \"type.googleapis.com/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "public static <T extends com.google.protobuf.Message> Any pack(\n" + " T message) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "public <T extends com.google.protobuf.Message> boolean is(\n" + " java.lang.Class<T> clazz) {\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " return getTypeUrl().equals(\n" + " getTypeUrl(defaultInstance.getDescriptorForType()));\n" + "}\n" + "\n" + "private volatile com.google.protobuf.Message cachedUnpackValue;\n" + "\n" + "public <T extends com.google.protobuf.Message> T unpack(\n" + " java.lang.Class<T> clazz)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " if (!is(clazz)) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " \"Type of the Any messsage does not match the given class.\");\n" + " }\n" + " if (cachedUnpackValue != null) {\n" + " return (T) cachedUnpackValue;\n" + " }\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " T result = (T) defaultInstance.getParserForType()\n" + " .parseFrom(getValue());\n" + " cachedUnpackValue = result;\n" + " return result;\n" + "}\n"); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index c3c37765..be5bfb07 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -122,6 +122,7 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); void GenerateParsingConstructor(io::Printer* printer); + void GenerateAnyMethods(io::Printer* printer); Context* context_; ClassNameResolver* name_resolver_; diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b180b4a7..b5f8e626 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -452,11 +452,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -736,11 +736,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -1232,11 +1233,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 8332202c..356520ec 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -310,11 +310,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -521,11 +521,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -885,11 +886,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(\n" + " input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 3accee92..8b6c75b8 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -45,7 +45,7 @@ #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> -#include <google/protobuf/compiler/java/java_enum.h> +#include <google/protobuf/compiler/java/java_enum_lite.h> #include <google/protobuf/compiler/java/java_extension.h> #include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> @@ -143,6 +143,17 @@ void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName(descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -190,7 +201,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator(descriptor_->enum_type(i), true, context_) + EnumLiteGenerator(descriptor_->enum_type(i), true, context_) .Generate(printer); } @@ -321,12 +332,12 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "protected final Object dynamicMethod(\n" " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" - " Object... args) {\n" + " Object arg0, Object arg1) {\n" " switch (method) {\n" " case PARSE_PARTIAL_FROM: {\n" " return new $classname$(" - " (com.google.protobuf.CodedInputStream) args[0],\n" - " (com.google.protobuf.ExtensionRegistryLite) args[1]);\n" + " (com.google.protobuf.CodedInputStream) arg0,\n" + " (com.google.protobuf.ExtensionRegistryLite) arg1);\n" " }\n" " case NEW_INSTANCE: {\n" " return new $classname$(\n" @@ -370,7 +381,25 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "case GET_DEFAULT_INSTANCE: {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "case GET_PARSER: {\n" + // Generally one would use the lazy initialization holder pattern for + // manipulating static fields but that has exceptional cost on Android as + // it will generate an extra class for every message. Instead, use the + // double-check locking pattern which works just as well. + " if (PARSER == null) {" + " synchronized ($classname$.class) {\n" + " if (PARSER == null) {\n" + " PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" + " }\n" + " }\n" + " }\n" + " return PARSER;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Outdent(); printer->Outdent(); @@ -413,18 +442,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateParser(printer); - // LITE_RUNTIME uses this to implement the *ForType methods at the - // GeneratedMessageLite level. - printer->Print( - "static {\n" - " com.google.protobuf.GeneratedMessageLite.onLoad(\n" - " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n" - " .PrototypeHolder<$classname$, Builder>(\n" - " DEFAULT_INSTANCE, PARSER));" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - // Extensions must be declared after the DEFAULT_INSTANCE is initialized // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. @@ -554,54 +571,54 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input);\n" + " return parser().parseDelimitedFrom(input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n" + " return parser().parseDelimitedFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -652,7 +669,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( "if (isInitialized == 1) return DEFAULT_INSTANCE;\n" "if (isInitialized == 0) return null;\n" "\n" - "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n"); + "boolean shouldMemoize = ((Boolean) arg0).booleanValue();\n"); // Check that all required fields in this message are set. // TODO(kenton): We can optimize this when we switch to putting all the @@ -778,7 +795,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( .GenerateDynamicMethodMakeImmutableCode(printer); } printer->Print( - "return null;"); + "return null;\n"); } // =================================================================== @@ -786,7 +803,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( io::Printer* printer) { printer->Print( - "return new Builder();"); + "return new Builder();\n"); } // =================================================================== @@ -796,9 +813,8 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( printer->Print( // Optimization: If other is the default instance, we know none of its // fields are set so we can skip the merge. - "Object arg = args[0];\n" - "if (arg == $classname$.getDefaultInstance()) return this;\n" - "$classname$ other = ($classname$) arg;\n", + "if (arg0 == $classname$.getDefaultInstance()) return this;\n" + "$classname$ other = ($classname$) arg0;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1151,9 +1167,11 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" - " new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" - "\n", + "private static volatile com.google.protobuf.Parser<$classname$> PARSER;\n" + "\n" + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return DEFAULT_INSTANCE.getParserForType();\n" + "}\n", "classname", descriptor_->name()); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 7bebe12a..178bbe19 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 217ff9b6..392333b8 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 7baead15..11bfc12d 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -39,7 +39,6 @@ #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> namespace google { diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 68e863cc..47e04659 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -36,6 +36,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> @@ -77,6 +78,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, " if (value == null) {\n" " throw new NullPointerException();\n" " }\n"; + (*variables)["writeString"] = + "com.google.protobuf.GeneratedMessage.writeString"; + (*variables)["computeStringSize"] = + "com.google.protobuf.GeneratedMessage.computeStringSize"; // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported // by the proto compiler @@ -433,7 +438,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $name$_);\n" "}\n"); } @@ -441,8 +446,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $name$_);\n" "}\n"); } @@ -689,7 +693,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $oneof_name$_);\n" "}\n"); } @@ -697,8 +701,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $oneof_name$_);\n" "}\n"); } @@ -1007,12 +1010,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " writeStringNoTag(output, $name$_.getRaw(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " $writeString$(output, $number$, $name$_.getRaw(i));\n" "}\n"); } } @@ -1026,8 +1029,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index 51bb245c..032715b7 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -36,6 +36,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> @@ -64,7 +65,8 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { SetCommonFieldVariables(descriptor, info, variables); - (*variables)["empty_list"] = "emptyLazyStringArrayList()"; + (*variables)["empty_list"] = + "com.google.protobuf.GeneratedMessageLite.emptyProtobufList()"; (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_init"] = @@ -101,7 +103,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_message"] = ""; (*variables)["is_field_present_message"] = - "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()"; + "!get" + (*variables)["capitalized_name"] + ".isEmpty()"; } // For repeated builders, the underlying list tracks mutability state. @@ -144,8 +146,9 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { return 0; } -// A note about how strings are handled. This code used to just store a String -// in the Message. This had two issues: +// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes, +// strings are not stored as java.lang.String in the Message because of two +// issues: // // 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded // strings, but rather fields that were raw bytes incorrectly marked @@ -160,22 +163,14 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { // it many cases, the field is never even read by the application code. This // avoids unnecessary conversions in the common use cases. // -// So now, the field for String is maintained as an Object reference which can -// either store a String or a ByteString. The code uses an instanceof check -// to see which one it has and converts to the other one if needed. It remembers -// the last value requested (in a thread safe manner) as this is most likely -// the one needed next. The thread safety is such that if two threads both -// convert the field because the changes made by each thread were not visible to -// the other, they may cause a conversion to happen more times than would -// otherwise be necessary. This was deemed better than adding synchronization -// overhead. It will not cause any corruption issues or affect the behavior of -// the API. The instanceof check is also highly optimized in the JVM and we -// decided it was better to reduce the memory overhead by not having two -// separate fields but rather use dynamic type checking. -// -// For single fields, the logic for this is done inside the generated code. For -// repeated fields, the logic is done in LazyStringArrayList and -// UnmodifiableLazyStringList. +// In the LITE_RUNTIME, we store strings as java.lang.String because we assume +// that the users of this runtime are not subject to proto1 constraints and are +// running code on devices that are user facing. That is, the developers are +// properly incentivized to only fetch the data they need to read and wish to +// reduce the number of allocations incurred when running on a user's device. + +// TODO(dweis): Consider dropping all of the *Bytes() methods. They really +// shouldn't be necessary or used on devices. void ImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { @@ -195,7 +190,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_;\n"); + "private java.lang.String $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { @@ -209,40 +204,13 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " $name$_ = s;\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8()) {\n" - " $name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" - " }\n" + " return $name$_;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " $name$_ = b;\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" - " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -273,7 +241,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_has_field_bit_message$\n" - " $name$_ = value;\n" + " $name$_ = value.toStringUtf8();\n" "}\n"); } @@ -368,7 +336,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -377,11 +345,6 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_has_field_bit_message$\n" - "$name$_ = bs;\n"); } } @@ -392,18 +355,24 @@ GenerateParsingDoneCode(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -458,51 +427,22 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return ref;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = b;\n" - " }\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8(ref);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -533,7 +473,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" + " $oneof_name$_ = value.toStringUtf8();\n" "}\n"); } @@ -603,7 +543,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -612,28 +552,29 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_oneof_case_message$;\n" - "$oneof_name$_ = bs;\n"); } } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -667,7 +608,7 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$com.google.protobuf.ProtocolStringList\n" + "$deprecation$java.util.List<String>\n" " get$capitalized_name$List();\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -685,12 +626,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private com.google.protobuf.LazyStringArrayList $name$_;\n"); + "private com.google.protobuf.Internal.ProtobufList<String> $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" - " get$capitalized_name$List() {\n" + "$deprecation$public java.util.List<String> get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -707,7 +647,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes(int index) {\n" - " return $name$_.getByteString(index);\n" + " return com.google.protobuf.ByteString.copyFromUtf8(\n" + " $name$_.get(index));\n" "}\n"); if (descriptor_->options().packed() && @@ -719,7 +660,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n" + " $name$_);\n" " }\n" "}\n"); @@ -764,7 +706,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.add(value.toStringUtf8());\n" "}\n"); } @@ -772,10 +714,10 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" + "$deprecation$public java.util.List<String>\n" " get$capitalized_name$List() {\n" - " return ((com.google.protobuf.LazyStringList)\n" - " instance.get$capitalized_name$List()).getUnmodifiableView();\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -875,20 +817,17 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "String s = input.readStringRequireUtf8();\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, "String s = input.readString();\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n"); } printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n"); if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, @@ -905,7 +844,7 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n" "while (input.getBytesUntilLimit() > 0) {\n"); if (CheckUtf8(descriptor_)) { @@ -932,6 +871,9 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. if (descriptor_->options().packed()) { printer->Print(variables_, "if (get$capitalized_name$List().size() > 0) {\n" @@ -939,18 +881,21 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " output.writeStringNoTag($name$_.get(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " output.writeString($number$, $name$_.get(i));\n" "}\n"); } } void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "{\n" " int dataSize = 0;\n"); @@ -959,7 +904,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " .computeStringSizeNoTag($name$_.get(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index a2eeee2d..895ff34a 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -44,6 +44,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/io/tokenizer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/map_util.h> diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 16012e96..007b001c 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -323,7 +323,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& service_location, const FileDescriptorProto* containing_file); - // Parse one statement within a message, enum, or service block, inclunding + // Parse one statement within a message, enum, or service block, including // final semicolon. bool ParseMessageStatement(DescriptorProto* message, const LocationRecorder& message_location, @@ -364,7 +364,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& extensions_location, const FileDescriptorProto* containing_file); - // Parse an "reserved" declaration. + // Parse a "reserved" declaration. bool ParseReserved(DescriptorProto* message, const LocationRecorder& message_location); bool ParseReservedNames(DescriptorProto* message, @@ -415,7 +415,7 @@ class LIBPROTOBUF_EXPORT Parser { Message* mutable_options); // Parse "required", "optional", or "repeated" and fill in "label" - // with the value. Returns true if shuch a label is consumed. + // with the value. Returns true if such a label is consumed. bool ParseLabel(FieldDescriptorProto::Label* label, const FileDescriptorProto* containing_file); diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index cdcaffde..2bebf1f3 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -48,6 +48,7 @@ #include <unistd.h> #endif +#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> diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index e7890fae..994bc392 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -629,28 +629,28 @@ int CodeGeneratorRequest::proto_file_size() const { void CodeGeneratorRequest::clear_proto_file() { proto_file_.Clear(); } - const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { +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) { +::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() { +::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } - 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_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +::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_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -1535,28 +1535,28 @@ int CodeGeneratorResponse::file_size() const { void CodeGeneratorResponse::clear_file() { file_.Clear(); } - const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { +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) { +::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() { +::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* +::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_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 6fcaea2e..ab79bdae 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -144,10 +144,10 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); ::google::protobuf::FileDescriptorProto* add_proto_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& - proto_file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_proto_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + proto_file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) private: @@ -378,10 +378,10 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& - file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* mutable_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& + file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) private: @@ -534,16 +534,16 @@ inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } -inline 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_; -} inline ::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_; } +inline 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_; +} // ------------------------------------------------------------------- @@ -784,16 +784,16 @@ inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorRe // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* CodeGeneratorResponse::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) return &file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 7b3b5fa3..4d500f90 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -58,6 +58,7 @@ #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/io/printer.h> diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 2ddac601..aa0f5fce 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -38,6 +38,7 @@ #include <string> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index a3cff1f8..85429924 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -42,6 +42,7 @@ #include <signal.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/message.h> #include <google/protobuf/stubs/substitute.h> |