diff options
Diffstat (limited to 'src/google/protobuf/compiler')
53 files changed, 3990 insertions, 1361 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index f9f27bd8..fc7df414 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -50,6 +50,9 @@ #include <google/protobuf/stubs/hash.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 5bc1fea9..6e1a204d 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -41,6 +41,9 @@ #include <unistd.h> #endif #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/descriptor.pb.h> @@ -48,6 +51,7 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/compiler/mock_code_generator.h> #include <google/protobuf/compiler/subprocess.h> #include <google/protobuf/io/printer.h> @@ -59,6 +63,7 @@ #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> + namespace google { namespace protobuf { namespace compiler { @@ -77,6 +82,10 @@ namespace compiler { namespace { +bool FileExists(const string& path) { + return File::Exists(path); +} + class CommandLineInterfaceTest : public testing::Test { protected: virtual void SetUp(); @@ -226,7 +235,7 @@ void CommandLineInterfaceTest::SetUp() { // If the temp directory already exists, it must be left over from a // previous run. Delete it. - if (File::Exists(temp_directory_)) { + if (FileExists(temp_directory_)) { File::DeleteRecursively(temp_directory_, NULL, NULL); } @@ -335,7 +344,7 @@ void CommandLineInterfaceTest::CreateTempFile( string::size_type slash_pos = name.find_last_of('/'); if (slash_pos != string::npos) { string dir = name.substr(0, slash_pos); - if (!File::Exists(temp_directory_ + "/" + dir)) { + if (!FileExists(temp_directory_ + "/" + dir)) { GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir, 0777)); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index c31cb5b3..32d5516e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -101,6 +101,15 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { } } + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + // For new enum semantics: generate min and max sentinel values equal to + // INT32_MIN and INT32_MAX + if (descriptor_->value_count() > 0) printer->Print(",\n"); + printer->Print(vars, + "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = INT32_MIN,\n" + "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = INT32_MAX"); + } + printer->Outdent(); printer->Print("\n};\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 20b18ade..17926135 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -87,9 +87,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_);\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " assert($type$_IsValid(value));\n" - " set_has_$name$();\n" + "inline void $classname$::set_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " assert($type$_IsValid(value));\n"); + } + printer->Print(variables_, + " $set_hasbit$\n" " $name$_ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); @@ -121,21 +125,27 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "int value;\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n" - "if ($type$_IsValid(value)) {\n" - " set_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + " input, &value)));\n"); + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables_, - "} else {\n" - " mutable_unknown_fields()->AddVarint($number$, value);\n"); + "set_$name$(static_cast< $type$ >(value));\n"); } else { - printer->Print( - "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(value);\n"); + printer->Print(variables_, + "if ($type$_IsValid(value)) {\n" + " set_$name$(static_cast< $type$ >(value));\n"); + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(variables_, + "} else {\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } else { + printer->Print( + "} else {\n" + " unknown_fields_stream.WriteVarint32(tag);\n" + " unknown_fields_stream.WriteVarint32(value);\n"); + } + printer->Print(variables_, + "}\n"); } - printer->Print(variables_, - "}\n"); } void EnumFieldGenerator:: @@ -174,18 +184,24 @@ void EnumOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return static_cast< $type$ >($oneof_prefix$$name$_);\n" " }\n" " return static_cast< $type$ >($default$);\n" "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " assert($type$_IsValid(value));\n" + "inline void $classname$::set_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " assert($type$_IsValid(value));\n"); + } + printer->Print(variables_, " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" " }\n" " $oneof_prefix$$name$_ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); } @@ -245,13 +261,21 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_get:$full_name$)\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n" - " assert($type$_IsValid(value));\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " assert($type$_IsValid(value));\n"); + } + printer->Print(variables_, " $name$_.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" - "inline void $classname$::add_$name$($type$ value) {\n" - " assert($type$_IsValid(value));\n" + "inline void $classname$::add_$name$($type$ value) {\n"); + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " assert($type$_IsValid(value));\n"); + } + printer->Print(variables_, " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n"); @@ -280,7 +304,7 @@ GenerateMergingCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } void RepeatedEnumFieldGenerator:: @@ -295,20 +319,26 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "int value;\n" "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n" - "if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + " input, &value)));\n"); + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables_, - "} else {\n" - " mutable_unknown_fields()->AddVarint($number$, value);\n"); + "add_$name$(static_cast< $type$ >(value));\n"); } else { - printer->Print( - "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(value);\n"); + printer->Print(variables_, + "if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n"); + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(variables_, + "} else {\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } else { + printer->Print( + "} else {\n" + " unknown_fields_stream.WriteVarint32(tag);\n" + " unknown_fields_stream.WriteVarint32(value);\n"); + } + printer->Print("}\n"); } - printer->Print("}\n"); } void RepeatedEnumFieldGenerator:: @@ -318,8 +348,15 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { // rarely be executed. printer->Print(variables_, "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" - " input,\n" - " &$type$_IsValid,\n" + " input,\n"); + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " NULL,\n"); + } else { + printer->Print(variables_, + " &$type$_IsValid,\n"); + } + printer->Print(variables_, " this->mutable_$name$())));\n"); } else { printer->Print(variables_, @@ -331,10 +368,17 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { " int value;\n" " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n" + " input, &value)));\n"); + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + printer->Print(variables_, + " add_$name$(static_cast< $type$ >(value));\n"); + } else { + printer->Print(variables_, " if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" - " }\n" + " }\n"); + } + printer->Print(variables_, "}\n" "input->PopLimit(limit);\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 1e9a40ac..85838ac3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -34,6 +34,9 @@ #include <google/protobuf/compiler/cpp/cpp_field.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_primitive_field.h> @@ -68,6 +71,20 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, ? " PROTOBUF_DEPRECATED" : ""; (*variables)["cppget"] = "Get"; + + if (HasFieldPresence(descriptor->file())) { + (*variables)["set_hasbit"] = + "set_has_" + FieldName(descriptor) + "();"; + (*variables)["clear_hasbit"] = + "clear_has_" + FieldName(descriptor) + "();"; + } else { + (*variables)["set_hasbit"] = ""; + (*variables)["clear_hasbit"] = ""; + } + + // By default, empty string, so that generic code used for both oneofs and + // singular fields can be written. + (*variables)["oneof_prefix"] = ""; } void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 0342c35e..088e5063 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -37,6 +37,9 @@ #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <google/protobuf/descriptor.h> @@ -124,6 +127,16 @@ class FieldGenerator { // Most field types don't need this, so the default implementation is empty. virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {} + // Generate a manual destructor invocation for use when the message is on an + // arena. The code that this method generates will be executed inside a + // shared-for-the-whole-message-class method registered with OwnDestructor(). + // The method should return |true| if it generated any code that requires a + // call; this allows the message generator to eliminate the OwnDestructor() + // registration if no fields require it. + virtual bool GenerateArenaDestructorCode(io::Printer* printer) const { + return false; + } + // Generate code that allocates the fields's default instance. virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/) const {} diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index fa194273..dc8bf613 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -34,6 +34,9 @@ #include <google/protobuf/compiler/cpp/cpp_file.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <set> #include <google/protobuf/compiler/cpp/cpp_enum.h> @@ -102,6 +105,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "#define PROTOBUF_$filename_identifier$__INCLUDED\n" "\n" "#include <string>\n" + "#include <stdint.h>\n" // INT32_MIN, INT32_MAX "\n", "filename", file_->name(), "filename_identifier", filename_identifier); @@ -131,7 +135,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // OK, it's now safe to #include other files. printer->Print( - "#include <google/protobuf/generated_message_util.h>\n"); + "#include <google/protobuf/arena.h>\n" + "#include <google/protobuf/arenastring.h>\n" + "#include <google/protobuf/generated_message_util.h>\n" + "#include <google/protobuf/metadata.h>\n"); if (file_->message_type_count() > 0) { if (HasDescriptorMethods(file_)) { printer->Print( @@ -181,6 +188,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// @@protoc_insertion_point(includes)\n"); + // Open namespace. GenerateNamespaceOpeners(printer); @@ -189,9 +197,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "\n" "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$ $adddescriptorsname$();\n", + "void $dllexport_decl$$adddescriptorsname$();\n", "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "dllexport_decl", options_.dllexport_decl); + "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); printer->Print( // Note that we don't put dllexport_decl on these because they are only @@ -295,7 +304,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { } printer->Print( "\n" - "} // namespace google\n} // namespace protobuf\n" + "} // namespace protobuf\n} // namespace google\n" "#endif // SWIG\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 4e4d8b6a..13d06f98 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 75d558ea..a2fb7162 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -36,6 +36,9 @@ #include <vector> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <utility> #include <google/protobuf/compiler/cpp/cpp_file.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index b7a47acb..63b0265e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -60,16 +60,17 @@ string DotsToColons(const string& name) { } const char* const kKeywordList[] = { - "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", - "catch", "char", "class", "compl", "const", "const_cast", "continue", - "default", "delete", "do", "double", "dynamic_cast", "else", "enum", - "explicit", "extern", "false", "float", "for", "friend", "goto", "if", - "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", - "operator", "or", "or_eq", "private", "protected", "public", "register", - "reinterpret_cast", "return", "short", "signed", "sizeof", "static", - "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", - "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", - "void", "volatile", "wchar_t", "while", "xor", "xor_eq" + "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", "char", "class", "compl", "const", + "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", + "or_eq", "private", "protected", "public", "register", "reinterpret_cast", + "return", "short", "signed", "sizeof", "static", "static_assert", + "static_cast", "struct", "switch", "template", "this", "thread_local", + "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", + "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" }; hash_set<string> MakeKeywordsMap() { diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 5d30240c..1cff17c8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -135,8 +135,15 @@ string SafeFunctionName(const Descriptor* descriptor, const FieldDescriptor* field, const string& prefix); -// Do message classes in this file use UnknownFieldSet? -// Otherwise, messages will store unknown fields in a string +// Returns true if unknown fields are preseved after parsing. +inline bool PreserveUnknownFields(const Descriptor* message) { + return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// If PreserveUnknownFields() is true, determines whether unknown +// fields will be stored in an UnknownFieldSet or a string. +// If PreserveUnknownFields() is false, this method will not be +// used. inline bool UseUnknownFieldSet(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } @@ -198,6 +205,28 @@ bool IsStringOrMessage(const FieldDescriptor* field); string UnderscoresToCamelCase(const string& input, bool cap_next_letter); +inline bool HasFieldPresence(const FileDescriptor* file) { + return file->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// Returns true if 'enum' semantics are such that unknown values are preserved +// in the enum field itself, rather than going to the UnknownFieldSet. +inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool SupportsArenas(const FileDescriptor* file) { + return true; +} + +inline bool SupportsArenas(const Descriptor* desc) { + return SupportsArenas(desc->file()); +} + +inline bool SupportsArenas(const FieldDescriptor* field) { + return SupportsArenas(field->file()); +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 3a9d2639..54a92ae4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -36,6 +36,9 @@ #include <google/protobuf/stubs/hash.h> #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <set> #include <utility> #include <vector> @@ -281,8 +284,67 @@ string MessageTypeProtoName(const FieldDescriptor* field) { return field->message_type()->full_name(); } +// Emits an if-statement with a condition that evaluates to true if |field| is +// considered non-default (will be sent over the wire), for message types +// without true field presence. Should only be called if +// !HasFieldPresence(message_descriptor). +bool EmitFieldNonDefaultCondition(io::Printer* printer, + const string& prefix, + const FieldDescriptor* field) { + // Merge and serialize semantics: primitive fields are merged/serialized only + // if non-zero (numeric) or non-empty (string). + if (!field->is_repeated() && !field->containing_oneof()) { + if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + printer->Print( + "if ($prefix$$name$().size() > 0) {\n", + "prefix", prefix, + "name", FieldName(field)); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + // Message fields still have has_$name$() methods. + printer->Print( + "if ($prefix$has_$name$()) {\n", + "prefix", prefix, + "name", FieldName(field)); + } else { + printer->Print( + "if ($prefix$$name$() != 0) {\n", + "prefix", prefix, + "name", FieldName(field)); + } + printer->Indent(); + return true; + } else if (field->containing_oneof()) { + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + return true; + } + return false; +} + +// Does the given field have a has_$name$() method? +bool HasHasMethod(const FieldDescriptor* field) { + if (HasFieldPresence(field->file())) { + // In proto1/proto2, every field has a has_$name$() method. + return true; + } + // For message types without true field presence, only fields with a message + // type have a has_$name$() method. + return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE; } +// Does the given field have a private (internal helper only) has_$name$() +// method? +bool HasPrivateHasMethod(const FieldDescriptor* field) { + // Only for oneofs in message types with no field presence. has_$name$(), + // based on the oneof case, is still useful internally for generated code. + return (!HasFieldPresence(field->file()) && + field->containing_oneof() != NULL); +} + +} // anonymous namespace + // =================================================================== MessageGenerator::MessageGenerator(const Descriptor* descriptor, @@ -312,6 +374,13 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, extension_generators_[i].reset( new ExtensionGenerator(descriptor->extension(i), options)); } + + num_required_fields_ = 0; + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + ++num_required_fields_; + } + } } MessageGenerator::~MessageGenerator() {} @@ -360,8 +429,13 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { if (field->is_repeated()) { printer->Print(vars, "inline int $name$_size() const$deprecation$;\n"); - } else { + } else if (HasHasMethod(field)) { printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n"); + } else if (HasPrivateHasMethod(field)) { + printer->Print(vars, + "private:\n" + "inline bool has_$name$() const$deprecation$;\n" + "public:\n"); } printer->Print(vars, "inline void clear_$name$()$deprecation$;\n"); @@ -410,32 +484,59 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { "}\n"); } else if (field->containing_oneof()) { // Singular field in a oneof + // N.B.: Without field presence, we do not use has-bits or generate + // has_$name$() methods, but oneofs still have set_has_$name$(). + // Oneofs also have has_$name$() but only as a private helper + // method, so that generated code is slightly cleaner (vs. comparing + // _oneof_case_[index] against a constant everywhere). vars["field_name"] = UnderscoresToCamelCase(field->name(), true); vars["oneof_name"] = field->containing_oneof()->name(); vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); printer->Print(vars, "inline bool $classname$::has_$name$() const {\n" " return $oneof_name$_case() == k$field_name$;\n" - "}\n" + "}\n"); + printer->Print(vars, "inline void $classname$::set_has_$name$() {\n" " _oneof_case_[$oneof_index$] = k$field_name$;\n" "}\n"); } else { // Singular field. - char buffer[kFastToBufferSize]; - vars["has_array_index"] = SimpleItoa(field->index() / 32); - vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), buffer); - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" - "}\n" - "inline void $classname$::set_has_$name$() {\n" - " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" - "}\n" - "inline void $classname$::clear_has_$name$() {\n" - " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" - "}\n" - ); + if (HasFieldPresence(descriptor_->file())) { + // N.B.: without field presence, we do not use has-bits or generate + // has_$name$() methods. + char buffer[kFastToBufferSize]; + vars["has_array_index"] = SimpleItoa(field->index() / 32); + vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), + buffer); + printer->Print(vars, + "inline bool $classname$::has_$name$() const {\n" + " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" + "}\n" + "inline void $classname$::set_has_$name$() {\n" + " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" + "}\n" + "inline void $classname$::clear_has_$name$() {\n" + " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" + "}\n" + ); + } else { + // Message fields have a has_$name$() method. + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + bool is_lazy = false; + if (is_lazy) { + printer->Print(vars, + "inline bool $classname$::has_$name$() const {\n" + " return !$name$_.IsCleared();\n" + "}\n"); + } else { + printer->Print(vars, + "inline bool $classname$::has_$name$() const {\n" + " return $name$_ != NULL;\n" + "}\n"); + } + } + } } // Generate clear_$name$() @@ -457,9 +558,11 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { printer->Print("}\n"); } else { field_generators_.get(field).GenerateClearingCode(printer); - if (!field->is_repeated()) { - printer->Print(vars, - "clear_has_$name$();\n"); + if (HasFieldPresence(descriptor_->file())) { + if (!field->is_repeated()) { + printer->Print(vars, + "clear_has_$name$();\n"); + } } } @@ -553,26 +656,41 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "\n"); - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( - "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" - " return _unknown_fields_;\n" - "}\n" - "\n" - "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n" - " return &_unknown_fields_;\n" - "}\n" - "\n"); - } else { + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" + " return _internal_metadata_.unknown_fields();\n" + "}\n" + "\n" + "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n" + " return _internal_metadata_.mutable_unknown_fields();\n" + "}\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"); + } + } + + // N.B.: We exclude GetArena() when arena support is disabled, falling back on + // MessageLite's implementation which returns NULL rather than generating our + // own method which returns NULL, in order to reduce code size. + if (SupportsArenas(descriptor_)) { + // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a + // MessageLite* (e.g., in RepeatedField::AddAllocated()). 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"); + "inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }\n" + "inline void* GetMaybeArenaPointer() const {\n" + " return MaybeArenaPtr();\n" + "}\n"); } // Only generate this member if it's not disabled. @@ -628,12 +746,18 @@ GenerateClassDefinition(io::Printer* printer) { } + if (SupportsArenas(descriptor_)) { + printer->Print(vars, + "void UnsafeArenaSwap($classname$* other);\n"); + } printer->Print(vars, "void Swap($classname$* other);\n" "\n" "// implements Message ----------------------------------------------\n" "\n" - "$classname$* New() const;\n"); + "inline $classname$* New() const { return New(NULL); }\n" + "\n" + "$classname$* New(::google::protobuf::Arena* arena) const;\n"); if (HasGeneratedMethods(descriptor_->file())) { if (HasDescriptorMethods(descriptor_->file())) { @@ -699,7 +823,41 @@ GenerateClassDefinition(io::Printer* printer) { "void SharedCtor();\n" "void SharedDtor();\n" "void SetCachedSize(int size) const;\n" - "public:\n"); + "void InternalSwap($classname$* other);\n", + "classname", classname_); + if (SupportsArenas(descriptor_)) { + printer->Print( + "protected:\n" + "explicit $classname$(::google::protobuf::Arena* arena);\n" + "private:\n" + "static void ArenaDtor(void* object);\n" + "inline void RegisterArenaDtor(::google::protobuf::Arena* arena);\n", + "classname", classname_); + } + + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "private:\n" + "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" + " return _internal_metadata_.arena();\n" + "}\n" + "inline void* MaybeArenaPtr() const {\n" + " return _internal_metadata_.raw_arena_ptr();\n" + "}\n" + "public:\n" + "\n"); + } else { + printer->Print( + "private:\n" + "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" + " return _arena_ptr_;\n" + "}\n" + "inline ::google::protobuf::Arena* MaybeArenaPtr() const {\n" + " return _arena_ptr_;\n" + "}\n" + "public:\n" + "\n"); + } if (HasDescriptorMethods(descriptor_->file())) { printer->Print( @@ -759,10 +917,18 @@ GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->is_repeated()) { - printer->Print( - "inline void set_has_$name$();\n", - "name", FieldName(descriptor_->field(i))); - if (!descriptor_->field(i)->containing_oneof()) { + // set_has_***() generated in all proto1/2 code and in oneofs (only) for + // messages without true field presence. + if (HasFieldPresence(descriptor_->file()) || + descriptor_->field(i)->containing_oneof()) { + printer->Print( + "inline void set_has_$name$();\n", + "name", FieldName(descriptor_->field(i))); + } + // clear_has_***() generated only for non-oneof fields + // in proto1/2. + if (!descriptor_->field(i)->containing_oneof() && + HasFieldPresence(descriptor_->file())) { printer->Print( "inline void clear_has_$name$();\n", "name", FieldName(descriptor_->field(i))); @@ -780,6 +946,14 @@ GenerateClassDefinition(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } + if (HasGeneratedMethods(descriptor_->file()) && + !descriptor_->options().message_set_wire_format() && + num_required_fields_ > 1) { + printer->Print( + "// helper for ByteSize()\n" + "int RequiredFieldsByteSizeFallback() const;\n\n"); + } + // Prepare decls for _cached_size_ and _has_bits_. Their position in the // output will be determined later. @@ -816,23 +990,32 @@ GenerateClassDefinition(io::Printer* printer) { if (UseUnknownFieldSet(descriptor_->file())) { printer->Print( - "::google::protobuf::UnknownFieldSet _unknown_fields_;\n" - "\n"); + "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { printer->Print( "::std::string _unknown_fields_;\n" + "::google::protobuf::Arena* _arena_ptr_;\n" "\n"); } - // _has_bits_ is frequently accessed, so to reduce code size and improve - // speed, it should be close to the start of the object. But, try not to - // waste space:_has_bits_ by itself always makes sense if its size is a - // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together - // will work well. - printer->Print(has_bits_decl.c_str()); - if ((sizeof_has_bits % 8) != 0) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; + if (SupportsArenas(descriptor_)) { + printer->Print( + "friend class ::google::protobuf::Arena;\n" + "typedef void InternalArenaConstructable_;\n" + "typedef void DestructorSkippable_;\n"); + } + + if (HasFieldPresence(descriptor_->file())) { + // _has_bits_ is frequently accessed, so to reduce code size and improve + // speed, it should be close to the start of the object. But, try not to + // waste space:_has_bits_ by itself always makes sense if its size is a + // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together + // will work well. + printer->Print(has_bits_decl.c_str()); + if ((sizeof_has_bits % 8) != 0) { + printer->Print(cached_size_decl.c_str()); + need_to_emit_cached_size = false; + } } // Field members: @@ -871,7 +1054,10 @@ GenerateClassDefinition(io::Printer* printer) { // For each oneof generate a union for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( - "union $camel_oneof_name$Union {\n", + "union $camel_oneof_name$Union {\n" + // explicit empty constructor is needed when union contains + // ArenaStringPtr members for string fields. + " $camel_oneof_name$Union() {}\n", "camel_oneof_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); printer->Indent(); @@ -1029,10 +1215,28 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { " new ::google::protobuf::internal::GeneratedMessageReflection(\n" " $classname$_descriptor_,\n" " $classname$::default_instance_,\n" - " $classname$_offsets_,\n" - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n" + " $classname$_offsets_,\n"); + if (!HasFieldPresence(descriptor_->file())) { + // If we don't have field presence, then _has_bits_ does not exist. + printer->Print(vars, + " -1,\n"); + } else { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n"); + } + + // Unknown field offset: either points to the unknown field set if embedded + // directly, or indicates that the unknown field set is stored as part of the + // internal metadata if not. + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(vars, + " -1,\n"); + } else { + printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" "$classname$, _unknown_fields_),\n"); + } + if (descriptor_->extension_range_count() > 0) { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" @@ -1054,8 +1258,23 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { " ::google::protobuf::DescriptorPool::generated_pool(),\n"); printer->Print(vars, " ::google::protobuf::MessageFactory::generated_factory(),\n"); + printer->Print(vars, - " sizeof($classname$));\n"); + " sizeof($classname$),\n"); + + // Arena offset: either an offset to the metadata struct that contains the + // arena pointer and unknown field set (in a space-efficient way) if we use + // that implementation strategy, or an offset directly to the arena pointer if + // not (because e.g. we don't have an unknown field set). + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _internal_metadata_));\n"); + } else { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _arena_));\n"); + } // Handle nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -1100,7 +1319,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { if ((descriptor_->oneof_decl_count() > 0) && HasDescriptorMethods(descriptor_->file())) { printer->Print( - "$classname$_default_oneof_instance_ = new $classname$OneofInstance;\n", + "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n", "classname", classname_); } @@ -1312,8 +1531,10 @@ GenerateSharedConstructorCode(io::Printer* printer) { } } - printer->Print( - "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + } for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( @@ -1331,6 +1552,14 @@ GenerateSharedDestructorCode(io::Printer* printer) { "void $classname$::SharedDtor() {\n", "classname", classname_); printer->Indent(); + if (SupportsArenas(descriptor_)) { + // Do nothing when the message is allocated in an arena. + printer->Print( + "if (GetArenaNoVirtual() != NULL) {\n" + " return;\n" + "}\n" + "\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()) { @@ -1381,19 +1610,107 @@ GenerateSharedDestructorCode(io::Printer* printer) { } void MessageGenerator:: +GenerateArenaDestructorCode(io::Printer* printer) { + // Generate the ArenaDtor() method. Track whether any fields actually produced + // code that needs to be called. + printer->Print( + "void $classname$::ArenaDtor(void* object) {\n", + "classname", classname_); + printer->Indent(); + + // This code is placed inside a static method, rather than an ordinary one, + // since that simplifies Arena's destructor list (ordinary function pointers + // rather than member function pointers). _this is the object being + // destructed. + printer->Print( + "$classname$* _this = reinterpret_cast< $classname$* >(object);\n" + // avoid an "unused variable" warning in case no fields have dtor code. + "(void)_this;\n", + "classname", classname_); + + bool need_registration = false; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (field_generators_.get(descriptor_->field(i)) + .GenerateArenaDestructorCode(printer)) { + need_registration = true; + } + } + printer->Outdent(); + printer->Print( + "}\n"); + + if (need_registration) { + printer->Print( + "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" + " if (arena != NULL) {" + " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" + " }\n" + "}\n", + "classname", classname_); + } else { + printer->Print( + "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" + "}\n", + "classname", classname_); + } +} + +void MessageGenerator:: GenerateStructors(io::Printer* printer) { string superclass = SuperClassName(descriptor_); + string initializer_with_arena; + if (UseUnknownFieldSet(descriptor_->file())) { + initializer_with_arena = "_internal_metadata_(arena)"; + } else { + initializer_with_arena = "_arena_ptr_(arena)"; + } + if (descriptor_->extension_range_count() > 0) { + initializer_with_arena = string("\n _extensions_(arena)") + + (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena; + } else { + initializer_with_arena = "\n " + initializer_with_arena; + } + + // Initialize member variables with arena constructor. + for (int i = 0; i < descriptor_->field_count(); i++) { + bool has_arena_constructor = descriptor_->field(i)->is_repeated(); + if (has_arena_constructor) { + initializer_with_arena += string(",\n ") + + FieldName(descriptor_->field(i)) + string("_(arena)"); + } + } + initializer_with_arena = superclass + "()" + + (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena; + + string initializer_null; + initializer_null = (UseUnknownFieldSet(descriptor_->file()) ? + ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)"); - // Generate the default constructor. printer->Print( - "$classname$::$classname$()\n" - " : $superclass$() {\n" - " SharedCtor();\n" - " // @@protoc_insertion_point(constructor:$full_name$)\n" - "}\n", - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name()); + "$classname$::$classname$()\n" + " : $superclass$() $initializer$ {\n" + " SharedCtor();\n" + " // @@protoc_insertion_point(constructor:$full_name$)\n" + "}\n", + "classname", classname_, + "superclass", superclass, + "full_name", descriptor_->full_name(), + "initializer", initializer_null); + + if (SupportsArenas(descriptor_)) { + printer->Print( + "\n" + "$classname$::$classname$(::google::protobuf::Arena* arena)\n" + " : $initializer$ {\n" + " SharedCtor();\n" + " RegisterArenaDtor(arena);\n" + " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" + "}\n", + "initializer", initializer_with_arena, + "classname", classname_, + "superclass", superclass, + "full_name", descriptor_->full_name()); + } printer->Print( "\n" @@ -1441,7 +1758,17 @@ GenerateStructors(io::Printer* printer) { // Generate the copy constructor. printer->Print( "$classname$::$classname$(const $classname$& from)\n" - " : $superclass$() {\n" + " : $superclass$()", + "classname", classname_, + "superclass", superclass, + "full_name", descriptor_->full_name()); + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + ",\n _internal_metadata_(NULL) {\n"); + } else if (!UseUnknownFieldSet(descriptor_->file())) { + printer->Print(",\n _arena_ptr_(NULL) {\n"); + } + printer->Print( " SharedCtor();\n" " MergeFrom(from);\n" " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" @@ -1467,6 +1794,11 @@ GenerateStructors(io::Printer* printer) { // Generate the shared destructor code. GenerateSharedDestructorCode(printer); + // Generate the arena-specific destructor code. + if (SupportsArenas(descriptor_)) { + GenerateArenaDestructorCode(printer); + } + // Generate SetCachedSize. printer->Print( "void $classname$::SetCachedSize(int size) const {\n" @@ -1512,11 +1844,23 @@ GenerateStructors(io::Printer* printer) { "\n", "classname", classname_); - printer->Print( - "$classname$* $classname$::New() const {\n" - " return new $classname$;\n" - "}\n", - "classname", classname_); + if (SupportsArenas(descriptor_)) { + printer->Print( + "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" + " return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n" + "}\n", + "classname", classname_); + } else { + printer->Print( + "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" + " $classname$* n = new $classname$;\n" + " if (arena != NULL) {\n" + " arena->Own(n);\n" + " }\n" + " return n;\n" + "}\n", + "classname", classname_); + } } @@ -1616,16 +1960,19 @@ GenerateClear(io::Printer* printer) { const string& memsets = memsets_for_chunk[i / 8]; uint32 mask = fields_mask_for_chunk[i / 8]; int count = popcnt(mask); + GOOGLE_DCHECK_GE(count, 1); if (count == 1 || (count <= 4 && count == memset_field_count_for_chunk[i / 8])) { // No "if" here because the chunk is trivial. } else { - printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$) {\n", - "index", SimpleItoa(i / 8 * 8), - "mask", SimpleItoa(mask)); - printer->Indent(); - chunk_block_in_progress = true; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (_has_bits_[$index$ / 32] & $mask$) {\n", + "index", SimpleItoa(i / 8 * 8), + "mask", SimpleItoa(mask)); + printer->Indent(); + chunk_block_in_progress = true; + } } printer->Print(memsets.c_str()); } @@ -1639,14 +1986,18 @@ GenerateClear(io::Printer* printer) { field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; - if (should_check_bit) { + bool have_enclosing_if = false; + if (should_check_bit && + // If no field presence, then always clear strings/messages as well. + HasFieldPresence(descriptor_->file())) { printer->Print("if (has_$name$()) {\n", "name", fieldname); printer->Indent(); + have_enclosing_if = true; } field_generators_.get(field).GenerateClearingCode(printer); - if (should_check_bit) { + if (have_enclosing_if) { printer->Outdent(); printer->Print("}\n"); } @@ -1678,16 +2029,22 @@ GenerateClear(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - // Step 5: Everything else. - printer->Print( - "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); - - if (UseUnknownFieldSet(descriptor_->file())) { + if (HasFieldPresence(descriptor_->file())) { + // Step 5: Everything else. printer->Print( - "mutable_unknown_fields()->Clear();\n"); - } else { - printer->Print( - "mutable_unknown_fields()->clear();\n"); + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + } + + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "if (_internal_metadata_.have_unknown_fields()) {\n" + " mutable_unknown_fields()->Clear();\n" + "}\n"); + } else { + printer->Print( + "mutable_unknown_fields()->clear();\n"); + } } printer->Outdent(); @@ -1748,12 +2105,42 @@ GenerateOneofClear(io::Printer* printer) { void MessageGenerator:: GenerateSwap(io::Printer* printer) { - // Generate the Swap member function. - printer->Print("void $classname$::Swap($classname$* other) {\n", + if (SupportsArenas(descriptor_)) { + // Generate the Swap member function. This is a lightweight wrapper around + // UnsafeArenaSwap() / MergeFrom() with temporaries, depending on the memory + // ownership situation: swapping across arenas or between an arena and a + // heap requires copying. + printer->Print( + "void $classname$::Swap($classname$* other) {\n" + " if (other == this) return;\n" + " if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n" + " InternalSwap(other);\n" + " } else {\n" + " $classname$ temp;\n" + " temp.MergeFrom(*this);\n" + " CopyFrom(*other);\n" + " other->CopyFrom(temp);\n" + " }\n" + "}\n" + "void $classname$::UnsafeArenaSwap($classname$* other) {\n" + " if (other == this) return;\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n" + " InternalSwap(other);\n" + "}\n", + "classname", classname_); + } else { + printer->Print( + "void $classname$::Swap($classname$* other) {\n" + " if (other == this) return;\n" + " InternalSwap(other);\n" + "}\n", + "classname", classname_); + } + + // Generate the UnsafeArenaSwap member function. + printer->Print("void $classname$::InternalSwap($classname$* other) {\n", "classname", classname_); printer->Indent(); - printer->Print("if (other != this) {\n"); - printer->Indent(); if (HasGeneratedMethods(descriptor_->file())) { for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1769,15 +2156,25 @@ GenerateSwap(io::Printer* printer) { "i", SimpleItoa(i)); } - for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { - printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", - "i", SimpleItoa(i)); + if (HasFieldPresence(descriptor_->file())) { + for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) { + printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", + "i", SimpleItoa(i)); + } } - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + } else { + printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n"); + } } else { - printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n"); + // Still swap internal_metadata as it may contain more than just + // unknown fields. + printer->Print( + "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); } printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { @@ -1789,8 +2186,6 @@ GenerateSwap(io::Printer* printer) { printer->Outdent(); printer->Print("}\n"); - printer->Outdent(); - printer->Print("}\n"); } void MessageGenerator:: @@ -1886,33 +2281,48 @@ GenerateMergeFrom(io::Printer* printer) { const FieldDescriptor* field = descriptor_->field(i); if (!field->is_repeated() && !field->containing_oneof()) { - // See above in GenerateClear for an explanation of this. - if (i / 8 != last_index / 8 || last_index < 0) { - if (last_index >= 0) { - printer->Outdent(); - printer->Print("}\n"); + if (HasFieldPresence(descriptor_->file())) { + // See above in GenerateClear for an explanation of this. + if (i / 8 != last_index / 8 || last_index < 0) { + if (last_index >= 0) { + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( + "if (from._has_bits_[$index$ / 32] & " + "(0xffu << ($index$ % 32))) {\n", + "index", SimpleItoa(field->index())); + printer->Indent(); } - printer->Print( - "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n", - "index", SimpleItoa(field->index())); - printer->Indent(); } last_index = i; - printer->Print( - "if (from.has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (from.has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + have_enclosing_if = true; + } else { + // Merge semantics without true field presence: primitive fields are + // merged only if non-zero (numeric) or non-empty (string). + have_enclosing_if = EmitFieldNonDefaultCondition( + printer, "from.", field); + } field_generators_.get(field).GenerateMergingCode(printer); - printer->Outdent(); - printer->Print("}\n"); + if (have_enclosing_if) { + printer->Outdent(); + printer->Print("}\n"); + } } } - if (last_index >= 0) { + if (HasFieldPresence(descriptor_->file()) && + last_index >= 0) { printer->Outdent(); printer->Print("}\n"); } @@ -1921,12 +2331,16 @@ GenerateMergeFrom(io::Printer* printer) { printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); } - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( - "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n"); - } else { - printer->Print( - "mutable_unknown_fields()->append(from.unknown_fields());\n"); + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "if (from._internal_metadata_.have_unknown_fields()) {\n" + " mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n" + "}\n"); + } else { + printer->Print( + "mutable_unknown_fields()->append(from.unknown_fields());\n"); + } } printer->Outdent(); @@ -2171,24 +2585,33 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } printer->Print(") {\n"); - if (UseUnknownFieldSet(descriptor_->file())) { - PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " mutable_unknown_fields()));\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" - " mutable_unknown_fields()));\n"); + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + PrintHandlingOptionalStaticInitializers( + descriptor_->file(), printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " mutable_unknown_fields()));\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + " mutable_unknown_fields()));\n"); + } else { + PrintHandlingOptionalStaticInitializers( + descriptor_->file(), printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " &unknown_fields_stream));\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + " &unknown_fields_stream));\n"); + } } else { PrintHandlingOptionalStaticInitializers( descriptor_->file(), printer, // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " &unknown_fields_stream));\n", + " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" - " &unknown_fields_stream));\n"); + " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); } printer->Print( " continue;\n" @@ -2196,14 +2619,19 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } // We really don't recognize this tag. Skip it. - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( - "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" - " input, tag, mutable_unknown_fields()));\n"); + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" + " input, tag, mutable_unknown_fields()));\n"); + } else { + printer->Print( + "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n" + " input, tag, &unknown_fields_stream));\n"); + } } else { printer->Print( - "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n" - " input, tag, &unknown_fields_stream));\n"); + "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n"); } if (descriptor_->field_count() > 0) { @@ -2232,11 +2660,15 @@ void MessageGenerator::GenerateSerializeOneField( io::Printer* printer, const FieldDescriptor* field, bool to_array) { PrintFieldComment(printer, field); - if (!field->is_repeated()) { + bool have_enclosing_if = false; + if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) { printer->Print( "if (has_$name$()) {\n", "name", FieldName(field)); printer->Indent(); + have_enclosing_if = true; + } else if (!HasFieldPresence(descriptor_->file())) { + have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field); } if (to_array) { @@ -2246,7 +2678,7 @@ void MessageGenerator::GenerateSerializeOneField( field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); } - if (!field->is_repeated()) { + if (have_enclosing_if) { printer->Outdent(); printer->Print("}\n"); } @@ -2386,28 +2818,69 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } } - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print("if (!unknown_fields().empty()) {\n"); - printer->Indent(); - if (to_array) { + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n"); + printer->Indent(); + if (to_array) { + printer->Print( + "target = " + "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " unknown_fields(), target);\n"); + } else { + printer->Print( + "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" + " unknown_fields(), output);\n"); + } + printer->Outdent(); + printer->Print( - "target = " - "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" - " unknown_fields(), target);\n"); + "}\n"); } else { printer->Print( - "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" - " unknown_fields(), output);\n"); + "output->WriteRaw(unknown_fields().data(),\n" + " unknown_fields().size());\n"); } - printer->Outdent(); + } +} - printer->Print( - "}\n"); - } else { - printer->Print( - "output->WriteRaw(unknown_fields().data(),\n" - " unknown_fields().size());\n"); +static vector<uint32> RequiredFieldsBitMask(const Descriptor* desc) { + vector<uint32> result; + uint32 mask = 0; + for (int i = 0; i < desc->field_count(); i++) { + if (i > 0 && i % 32 == 0) { + result.push_back(mask); + mask = 0; + } + if (desc->field(i)->is_required()) { + mask |= (1 << (i & 31)); + } + } + if (mask != 0) { + result.push_back(mask); } + return result; +} + +// Create an expression that evaluates to +// "for all i, (_has_bits_[i] & masks[i]) == masks[i]" +// masks is allowed to be shorter than _has_bits_, but at least one element of +// masks must be non-zero. +static string ConditionalToCheckBitmasks(const vector<uint32>& masks) { + vector<string> parts; + for (int i = 0; i < masks.size(); i++) { + if (masks[i] == 0) continue; + char buffer[kFastToBufferSize]; + FastHex32ToBuffer(masks[i], buffer); + string m = StrCat("0x", buffer); + // Each xor evaluates to 0 if the expected bits are present. + parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")")); + } + GOOGLE_CHECK(!parts.empty()); + // If we have multiple parts, each expected to be 0, then bitwise-or them. + string result = parts.size() == 1 ? parts[0] : + StrCat("(", Join(parts, "\n | "), ")"); + return result + " == 0"; } void MessageGenerator:: @@ -2420,8 +2893,10 @@ GenerateByteSize(io::Printer* printer) { "classname", classname_); GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); printer->Print( + "if (_internal_metadata_.have_unknown_fields()) {\n" " total_size += ::google::protobuf::internal::WireFormat::\n" - " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"); + " ComputeUnknownMessageSetItemsSize(unknown_fields());\n" + "}\n"); printer->Print( " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" " _cached_size_ = total_size;\n" @@ -2431,6 +2906,33 @@ GenerateByteSize(io::Printer* printer) { return; } + if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) { + // Emit a function (rarely used, we hope) that handles the required fields + // by checking for each one individually. + printer->Print( + "int $classname$::RequiredFieldsByteSizeFallback() const {\n", + "classname", classname_); + printer->Indent(); + printer->Print("int total_size = 0;\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->is_required()) { + printer->Print("\n" + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + PrintFieldComment(printer, field); + field_generators_.get(field).GenerateByteSize(printer); + printer->Outdent(); + printer->Print("}\n"); + } + } + printer->Print("\n" + "return total_size;\n"); + printer->Outdent(); + printer->Print("}\n"); + } + printer->Print( "int $classname$::ByteSize() const {\n", "classname", classname_); @@ -2439,45 +2941,121 @@ GenerateByteSize(io::Printer* printer) { "int total_size = 0;\n" "\n"); - int last_index = -1; + // Handle required fields (if any). We expect all of them to be + // present, so emit one conditional that checks for that. If they are all + // present then the fast path executes; otherwise the slow path executes. + if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) { + // The fast path works if all required fields are present. + vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(descriptor_); + printer->Print((string("if (") + + ConditionalToCheckBitmasks(masks_for_has_bits) + + ") { // All required fields are present.\n").c_str()); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!field->is_required()) continue; + PrintFieldComment(printer, field); + field_generators_.get(field).GenerateByteSize(printer); + printer->Print("\n"); + } + printer->Outdent(); + printer->Print("} else {\n" // the slow path + " total_size += RequiredFieldsByteSizeFallback();\n" + "}\n"); + } else { + // num_required_fields_ <= 1: no need to be tricky + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!field->is_required()) continue; + PrintFieldComment(printer, field); + printer->Print("if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + field_generators_.get(field).GenerateByteSize(printer); + printer->Outdent(); + printer->Print("}\n"); + } + } + // Handle optional fields (worry below about repeateds, oneofs, etc.). + // These are handled in chunks of 8. The first chunk is + // the non-requireds-non-repeateds-non-unions-non-extensions in + // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7), + // and the second chunk is the same for + // descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15), + // etc. + hash_map<int, uint32> fields_mask_for_chunk; for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); + if (!field->is_required() && !field->is_repeated() && + !field->containing_oneof()) { + fields_mask_for_chunk[i / 8] |= static_cast<uint32>(1) << (i % 32); + } + } - if (!field->is_repeated() && !field->containing_oneof()) { + int last_index = -1; + bool chunk_block_in_progress = false; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!field->is_required() && !field->is_repeated() && + !field->containing_oneof()) { // See above in GenerateClear for an explanation of this. // TODO(kenton): Share code? Unclear how to do so without // over-engineering. - if ((i / 8) != (last_index / 8) || - last_index < 0) { - if (last_index >= 0) { + if (i / 8 != last_index / 8 || last_index < 0) { + // End previous chunk, if there was one. + if (chunk_block_in_progress) { printer->Outdent(); printer->Print("}\n"); + chunk_block_in_progress = false; + } + // Start chunk. + uint32 mask = fields_mask_for_chunk[i / 8]; + int count = popcnt(mask); + GOOGLE_DCHECK_GE(count, 1); + if (count == 1) { + // No "if" here because the chunk is trivial. + } else { + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (_has_bits_[$index$ / 32] & $mask$) {\n", + "index", SimpleItoa(i), + "mask", SimpleItoa(mask)); + printer->Indent(); + chunk_block_in_progress = true; + } } - printer->Print( - "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n", - "index", SimpleItoa(field->index())); - printer->Indent(); } last_index = i; PrintFieldComment(printer, field); - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + have_enclosing_if = true; + } else { + // Without field presence: field is serialized only if it has a + // non-default value. + have_enclosing_if = EmitFieldNonDefaultCondition( + printer, "this->", field); + } field_generators_.get(field).GenerateByteSize(printer); - printer->Outdent(); - printer->Print( - "}\n" - "\n"); + if (have_enclosing_if) { + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + } } } - if (last_index >= 0) { + if (chunk_block_in_progress) { printer->Outdent(); printer->Print("}\n"); } @@ -2532,19 +3110,19 @@ GenerateByteSize(io::Printer* printer) { "\n"); } - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print("if (!unknown_fields().empty()) {\n"); - printer->Indent(); - printer->Print( - "total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" - " unknown_fields());\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print( - "total_size += unknown_fields().size();\n" - "\n"); + if (PreserveUnknownFields(descriptor_)) { + if (UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "if (_internal_metadata_.have_unknown_fields()) {\n" + " total_size +=\n" + " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" + " unknown_fields());\n" + "}\n"); + } else { + printer->Print( + "total_size += unknown_fields().size();\n" + "\n"); + } } // We update _cached_size_ even though this is a const method. In theory, @@ -2569,27 +3147,29 @@ GenerateIsInitialized(io::Printer* printer) { "classname", classname_); printer->Indent(); - // Check that all required fields in this message are set. We can do this - // most efficiently by checking 32 "has bits" at a time. - int has_bits_array_size = (descriptor_->field_count() + 31) / 32; - for (int i = 0; i < has_bits_array_size; i++) { - uint32 mask = 0; - for (int bit = 0; bit < 32; bit++) { - int index = i * 32 + bit; - if (index >= descriptor_->field_count()) break; - const FieldDescriptor* field = descriptor_->field(index); - - if (field->is_required()) { - mask |= 1 << bit; + if (HasFieldPresence(descriptor_->file())) { + // Check that all required fields in this message are set. We can do this + // most efficiently by checking 32 "has bits" at a time. + int has_bits_array_size = (descriptor_->field_count() + 31) / 32; + for (int i = 0; i < has_bits_array_size; i++) { + uint32 mask = 0; + for (int bit = 0; bit < 32; bit++) { + int index = i * 32 + bit; + if (index >= descriptor_->field_count()) break; + const FieldDescriptor* field = descriptor_->field(index); + + if (field->is_required()) { + mask |= 1 << bit; + } } - } - if (mask != 0) { - char buffer[kFastToBufferSize]; - printer->Print( - "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", - "i", SimpleItoa(i), - "mask", FastHex32ToBuffer(mask, buffer)); + if (mask != 0) { + char buffer[kFastToBufferSize]; + printer->Print( + "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", + "i", SimpleItoa(i), + "mask", FastHex32ToBuffer(mask, buffer)); + } } } @@ -2607,7 +3187,7 @@ GenerateIsInitialized(io::Printer* printer) { "name", FieldName(field)); } else { if (field->options().weak()) { - // For weak fields, use the data member (google::protobuf::Message*) instead + // For weak fields, use the data member (::google::protobuf::Message*) instead // of the getter to avoid a link dependency on the weak message type // which is only forward declared. printer->Print( diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index bfd3cec1..a781c234 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> #include <google/protobuf/compiler/cpp/cpp_field.h> @@ -58,8 +61,7 @@ class ExtensionGenerator; // extension.h class MessageGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit MessageGenerator(const Descriptor* descriptor, - const Options& options); + MessageGenerator(const Descriptor* descriptor, const Options& options); ~MessageGenerator(); // Header stuff. @@ -130,6 +132,8 @@ class MessageGenerator { void GenerateSharedConstructorCode(io::Printer* printer); // Generate the shared destructor code. void GenerateSharedDestructorCode(io::Printer* printer); + // Generate the arena-specific destructor code. + void GenerateArenaDestructorCode(io::Printer* printer); // Generate standard Message methods. void GenerateClear(io::Printer* printer); @@ -162,6 +166,7 @@ class MessageGenerator { scoped_array<scoped_ptr<MessageGenerator> > nested_generators_; scoped_array<scoped_ptr<EnumGenerator> > enum_generators_; scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_; + int num_required_fields_; bool uses_string_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 6ac15a5a..da1ec60b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -86,6 +86,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline $type$* mutable_$name$()$deprecation$;\n" "inline $type$* $release_name$()$deprecation$;\n" "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "inline $type$* unsafe_arena_release_$name$()$deprecation$;\n" + "inline void unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$)$deprecation$;\n"); + } } void MessageFieldGenerator:: @@ -101,36 +107,157 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { // Without. " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); - printer->Print(variables_, - "}\n" - "inline $type$* $classname$::mutable_$name$() {\n" - " set_has_$name$();\n" - " if ($name$_ == NULL) $name$_ = new $type$;\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline $type$* $classname$::$release_name$() {\n" - " clear_has_$name$();\n" - " $type$* temp = $name$_;\n" - " $name$_ = NULL;\n" - " return temp;\n" - "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" - " delete $name$_;\n" - " $name$_ = $name$;\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " } else {\n" - " clear_has_$name$();\n" - " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "}\n" + "inline $type$* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n"); + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } + printer->Print(variables_, " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline $type$* $classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " if (GetArenaNoVirtual() != NULL) {\n" + " if ($name$_ == NULL) {\n" + " return NULL;\n" + " } else {\n" + " $type$* temp = new $type$;\n" + " temp->MergeFrom(*$name$_);\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + " } else {\n" + " $type$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + "}\n" + "inline $type$* $classname$::unsafe_arena_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" + " if (GetArenaNoVirtual() == 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_, + " if (GetArenaNoVirtual() != NULL && \n" + " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" + " GetArenaNoVirtual()->Own($name$);\n" + " } else if (GetArenaNoVirtual() !=\n" + " ::google::protobuf::Arena::GetArena($name$)) {\n" + " $type$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } else { + printer->Print(variables_, + " if (GetArenaNoVirtual() != NULL) {\n" + " GetArenaNoVirtual()->Own($name$);\n" + " }\n"); + } + + printer->Print(variables_, + " }\n" + " $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" + "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$) {\n" + // If we're not on an arena, free whatever we were holding before. + // (If we are on arena, we can just forget the earlier pointer.) + " if (GetArenaNoVirtual() == NULL) {\n" + " delete $name$_;\n" + " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" + ":$full_name$)\n" + "}\n"); + } else { + printer->Print(variables_, + "}\n" + "inline $type$* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n" + " $name$_ = new $type$;\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\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" + " delete $name$_;\n"); + + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + " if ($name$ != NULL && $name$->GetArena() != NULL) {\n" + " $type$* new_$name$ = new $type$;\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:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, - "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); + 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 ($name$_ != NULL) delete $name$_;\n" + "$name$_ = NULL;\n"); + } else { + printer->Print(variables_, + "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); + } } void MessageFieldGenerator:: @@ -198,43 +325,165 @@ MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\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" - " }\n" - " return $oneof_prefix$$name$_;\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" - " return temp;\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" - " }\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"); + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + " $oneof_prefix$$name$_ = \n" + " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + " $oneof_prefix$$name$_ = \n" + " ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); + } + printer->Print(variables_, + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $oneof_prefix$$name$_;\n" + "}\n" + "inline $type$* $classname$::$release_name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " if (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" + " return temp;\n" + " } else {\n" + " $type$* temp = $oneof_prefix$$name$_;\n" + " $oneof_prefix$$name$_ = 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" + " if ($name$) {\n"); + + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables_, + // 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" + " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" + " GetArenaNoVirtual()->Own($name$);\n" + " } else if (GetArenaNoVirtual() !=\n" + " ::google::protobuf::Arena::GetArena($name$)) {\n" + " $type$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } else { + printer->Print(variables_, + " if (GetArenaNoVirtual() != NULL) {\n" + " GetArenaNoVirtual()->Own($name$);\n" + " }\n"); + } + + printer->Print(variables_, + " set_has_$name$();\n" + " $oneof_prefix$$name$_ = $name$;\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\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. + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_ = $name$;\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\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" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $oneof_prefix$$name$_;\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" + " return temp;\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + " 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" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } + printer->Print(variables_, + " set_has_$name$();\n" + " $oneof_prefix$$name$_ = $name$;\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } } void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - // if it is the active field, it cannot be NULL. - printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "if (GetArenaNoVirtual() == NULL) {\n" + " delete $oneof_prefix$$name$_;\n" + "}\n"); + } else { + printer->Print(variables_, + "delete $oneof_prefix$$name$_;\n"); + } } void MessageOneofFieldGenerator:: @@ -318,7 +567,7 @@ GenerateMergingCode(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } void RepeatedMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc index 2dbf14ce..26cefb2e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -35,6 +35,9 @@ // worth. #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/command_line_interface.h> @@ -69,6 +72,100 @@ class TestGenerator : public CodeGenerator { TryInsert("test.pb.cc", "includes", context); TryInsert("test.pb.cc", "namespace_scope", context); TryInsert("test.pb.cc", "global_scope", context); + + // Check field accessors for an optional int32: + TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context); + + // Check field accessors for a repeated int32: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context); + + // Check field accessors for a required string: + TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString", + context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context); + + // Check field accessors for a repeated string: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context); + + // Check field accessors for an int inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context); + + // Check field accessors for a string inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context); + TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context); + + // Check field accessors for an optional message: + TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context); + + // Check field accessors for a repeated message: + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage", + context); + + // Check field accessors for a message inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context); + TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfMessage", context); + + // Check field accessors for an optional enum: + TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context); + + // Check field accessors for a repeated enum: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context); + + // Check field accessors for an enum inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context); + + // Check field accessors for a required cord: + TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context); + + // Check field accessors for a repeated cord: + TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context); + TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context); + + // Check field accessors for a cord inside oneof{}: + TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context); + TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context); + TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context); + return true; } @@ -88,8 +185,39 @@ TEST(CppPluginTest, PluginTest) { GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto", "syntax = \"proto2\";\n" "package foo;\n" + "\n" + "enum Thud { VALUE = 0; }\n" + "\n" "message Bar {\n" " message Baz {}\n" + " optional int32 optInt = 1;\n" + " repeated int32 repeatedInt = 2;\n" + "\n" + " required string requiredString = 3;\n" + " repeated string repeatedString = 4;\n" + "\n" + " optional Baz optMessage = 6;\n" + " repeated Baz repeatedMessage = 7;\n" + "\n" + " optional Thud optEnum = 8;\n" + " repeated Thud repeatedEnum = 9;\n" + "\n" + " required string requiredCord = 10 [\n" + " ctype = CORD\n" + " ];\n" + " repeated string repeatedCord = 11 [\n" + " ctype = CORD\n" + " ];\n" + "\n" + " oneof Qux {\n" + " int64 oneOfInt = 20;\n" + " string oneOfString = 21;\n" + " Baz oneOfMessage = 22;\n" + " Thud oneOfEnum = 23;" + " string oneOfCord = 24 [\n" + " ctype = CORD\n" + " ];\n" + " }\n" "}\n", true)); diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 44290a31..9a2c930e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -129,7 +129,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return $name$_;\n" "}\n" "inline void $classname$::set_$name$($type$ value) {\n" - " set_has_$name$();\n" + " $set_hasbit$\n" " $name$_ = value;\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); @@ -161,7 +161,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" " $type$, $wire_format_field_type$>(\n" " input, &$name$_)));\n" - "set_has_$name$();\n"); + "$set_hasbit$\n"); } void PrimitiveFieldGenerator:: @@ -207,6 +207,7 @@ void PrimitiveOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $oneof_prefix$$name$_;\n" " }\n" @@ -218,6 +219,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " set_has_$name$();\n" " }\n" " $oneof_prefix$$name$_ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n"); } @@ -330,7 +332,7 @@ GenerateMergingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } void RepeatedPrimitiveFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 180d236b..a2a8c81c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -52,9 +52,14 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["default_length"] = SimpleItoa(descriptor->default_value_string().length()); - (*variables)["default_variable"] = descriptor->default_value_string().empty() - ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()" - : "_default_" + FieldName(descriptor) + "_"; + string default_variable_string = + descriptor->default_value_string().empty() + ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()" + : "_default_" + FieldName(descriptor) + "_"; + (*variables)["default_variable"] = default_variable_string; + (*variables)["default_value_init"] = + descriptor->default_value_string().empty() + ? "" : "*" + default_variable_string; (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; // NOTE: Escaped here to unblock proto1->proto2 migration. @@ -63,6 +68,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); + + (*variables)["string_piece"] = "::std::string"; } } // namespace @@ -80,7 +87,19 @@ StringFieldGenerator::~StringFieldGenerator() {} void StringFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, "::std::string* $name$_;\n"); + // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for + // string fields, even when SupportArenas(descriptor_) == false. Why? + // The simple answer is to avoid unmaintainable complexity. The reflection + // code assumes ArenaStringPtrs. These are *almost* in-memory-compatible with + // string*, except for the pointer tags and related ownership semantics. We + // could modify the runtime code to use string* for the not-supporting-arenas + // case, but this would require a way to detect which type of class was + // generated (adding overhead and complexity to GeneratedMessageReflection) + // and littering the runtime code paths with conditionals. It's simpler to + // stick with this but use lightweight accessors that assume arena == NULL. + // There should be very little overhead anyway because it's just a tagged + // pointer in-memory. + printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n"); } void StringFieldGenerator:: @@ -125,6 +144,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline ::std::string* mutable_$name$()$deprecation$;\n" "inline ::std::string* $release_name$()$deprecation$;\n" "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "inline ::std::string* unsafe_arena_release_$name$()$deprecation$;\n" + "inline void unsafe_arena_set_allocated_$name$(\n" + " ::std::string* $name$)$deprecation$;\n"); + } if (descriptor_->options().ctype() != FieldOptions::STRING) { @@ -136,74 +161,113 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void StringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return *$name$_;\n" - "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" - " set_has_$name$();\n" - " if ($name$_ == $default_variable$) {\n" - " $name$_ = new ::std::string;\n" - " }\n" - " $name$_->assign(value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" - " set_has_$name$();\n" - " if ($name$_ == $default_variable$) {\n" - " $name$_ = new ::std::string;\n" - " }\n" - " $name$_->assign(value);\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "inline " - "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" - " set_has_$name$();\n" - " if ($name$_ == $default_variable$) {\n" - " $name$_ = new ::std::string;\n" - " }\n" - " $name$_->assign(reinterpret_cast<const char*>(value), size);\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" - " set_has_$name$();\n" - " if ($name$_ == $default_variable$) {\n"); - if (descriptor_->default_value_string().empty()) { + if (SupportsArenas(descriptor_)) { printer->Print(variables_, - " $name$_ = new ::std::string;\n"); + "inline const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.Get($default_variable$);\n" + "}\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(const char* value) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, $string_piece$(value),\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value,\n" + " size_t size) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, $string_piece$(\n" + " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" + "}\n" + "inline ::std::string* $classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" + "}\n" + "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " $clear_hasbit$\n" + " return $name$_.UnsafeArenaRelease($default_variable$,\n" + " GetArenaNoVirtual());\n" + "}\n" + "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.SetAllocated($default_variable$, $name$,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" + " ::std::string* $name$) {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $set_hasbit$\n" + " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" + " $name$, GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } else { + // No-arena case. printer->Print(variables_, - " $name$_ = new ::std::string(*$default_variable$);\n"); + "inline const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.GetNoArena($default_variable$);\n" + "}\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(const char* value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value, " + "size_t size) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$,\n" + " $string_piece$(reinterpret_cast<const char*>(value), size));\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.MutableNoArena($default_variable$);\n" + "}\n" + "inline ::std::string* $classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " return $name$_.ReleaseNoArena($default_variable$);\n" + "}\n" + "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.SetAllocatedNoArena($default_variable$, $name$);\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } - printer->Print(variables_, - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" - " clear_has_$name$();\n" - " if ($name$_ == $default_variable$) {\n" - " return NULL;\n" - " } else {\n" - " ::std::string* temp = $name$_;\n" - " $name$_ = const_cast< ::std::string*>($default_variable$);\n" - " return temp;\n" - " }\n" - "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if ($name$_ != $default_variable$) {\n" - " delete $name$_;\n" - " }\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $name$_ = $name$;\n" - " } else {\n" - " clear_has_$name$();\n" - " $name$_ = const_cast< ::std::string*>($default_variable$);\n" - " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); } void StringFieldGenerator:: @@ -217,16 +281,26 @@ GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { void StringFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "if ($name$_ != $default_variable$) {\n" - " $name$_->clear();\n" - "}\n"); + // Two-dimension specialization here: supporting arenas or not, and default + // value is the empty string or not. Complexity here ensures the minimal + // number of branches / amount of extraneous code at runtime (given that the + // below methods are inlined one-liners)! + if (SupportsArenas(descriptor_)) { + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); + } } else { - printer->Print(variables_, - "if ($name$_ != $default_variable$) {\n" - " $name$_->assign(*$default_variable$);\n" - "}\n"); + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "$name$_.ClearToEmptyNoArena($default_variable$);\n"); + } else { + printer->Print(variables_, + "$name$_.ClearToDefaultNoArena($default_variable$);\n"); + } } } @@ -237,21 +311,24 @@ GenerateMergingCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); + printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); } void StringFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = const_cast< ::std::string*>($default_variable$);\n"); + "$name$_.UnsafeSetDefault($default_variable$);\n"); } void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { - printer->Print(variables_, - "if ($name$_ != $default_variable$) {\n" - " delete $name$_;\n" - "}\n"); + if (SupportsArenas(descriptor_)) { + printer->Print(variables_, + "$name$_.Destroy($default_variable$, GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + "$name$_.DestroyNoArena($default_variable$);\n"); + } } void StringFieldGenerator:: @@ -276,13 +353,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" " input, this->mutable_$name$()));\n"); + if (HasUtf8Verification(descriptor_->file()) && descriptor_->type() == FieldDescriptor::TYPE_STRING) { printer->Print(variables_, "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" " this->$name$().data(), this->$name$().length(),\n" " ::google::protobuf::internal::WireFormat::PARSE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } } @@ -294,7 +372,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" " this->$name$().data(), this->$name$().length(),\n" " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } printer->Print(variables_, "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n" @@ -309,7 +387,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" " this->$name$().data(), this->$name$().length(),\n" " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } printer->Print(variables_, "target =\n" @@ -338,84 +416,186 @@ StringOneofFieldGenerator::~StringOneofFieldGenerator() {} void StringOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$() const {\n" - " if (has_$name$()) {\n" - " return *$oneof_prefix$$name$_;\n" - " }\n"); - if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - " return ::google::protobuf::internal::GetEmptyStringAlreadyInited();\n"); - } else { - printer->Print(variables_, - " return *$default_variable$;\n"); - } - printer->Print(variables_, - "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new ::std::string;\n" - " }\n" - " $oneof_prefix$$name$_->assign(value);\n" - "}\n" - "inline void $classname$::set_$name$(const char* value) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new ::std::string;\n" - " }\n" - " $oneof_prefix$$name$_->assign(value);\n" - "}\n" - "inline " - "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new ::std::string;\n" - " }\n" - " $oneof_prefix$$name$_->assign(\n" - " reinterpret_cast<const char*>(value), size);\n" - "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n"); - if (descriptor_->default_value_string().empty()) { + if (SupportsArenas(descriptor_)) { printer->Print(variables_, - " $oneof_prefix$$name$_ = new ::std::string;\n"); + "inline const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return $oneof_prefix$$name$_.Get($default_variable$);\n" + " }\n" + " return *$default_variable$;\n" + "}\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.Set($default_variable$, value,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(const char* value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.Set($default_variable$,\n" + " $string_piece$(value), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value,\n" + " size_t size) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n" + " reinterpret_cast<const char*>(value), size),\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " return $oneof_prefix$$name$_.Mutable($default_variable$,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + "}\n" + "inline ::std::string* $classname$::$release_name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.Release($default_variable$,\n" + " GetArenaNoVirtual());\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n" + " $default_variable$, GetArenaNoVirtual());\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$ != NULL) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n" + " GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$(" + "::std::string* $name$) {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " + "$name$, GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } else { + // No-arena case. printer->Print(variables_, - " $oneof_prefix$$name$_ = new ::std::string(*$default_variable$);\n"); + "inline const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n" + " }\n" + " return *$default_variable$;\n" + "}\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::set_$name$(const char* value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n" + " $string_piece$(value));\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.SetNoArena($default_variable$, $string_piece$(\n" + " reinterpret_cast<const char*>(value), size));\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline ::std::string* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" + "}\n" + "inline ::std::string* $classname$::$release_name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$ != NULL) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n" + " $name$);\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } - printer->Print(variables_, - " }\n" - " return $oneof_prefix$$name$_;\n" - "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " ::std::string* 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$(::std::string* $name$) {\n" - " clear_$oneof_name$();\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" - " }\n" - "}\n"); } void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + "$oneof_prefix$$name$_.Destroy($default_variable$,\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"); + } } void StringOneofFieldGenerator:: @@ -425,25 +605,45 @@ GenerateSwappingCode(io::Printer* printer) const { void StringOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - if (!descriptor_->default_value_string().empty()) { + printer->Print(variables_, + " const_cast< ::google::protobuf::internal::ArenaStringPtr*>(" + "&$classname$_default_oneof_instance_->$name$_)->UnsafeSetDefault(" + "$default_variable$);\n"); +} + +void StringOneofFieldGenerator:: +GenerateDestructorCode(io::Printer* printer) const { + if (SupportsArenas(descriptor_)) { printer->Print(variables_, - " $classname$_default_oneof_instance_->$name$_ = " - "$classname$::$default_variable$;\n"); + "if (has_$name$()) {\n" + " $oneof_prefix$$name$_.Destroy($default_variable$,\n" + " GetArenaNoVirtual());\n" + "}\n"); } else { printer->Print(variables_, - " $classname$_default_oneof_instance_->$name$_ = " - "$default_variable$;\n"); + "if (has_$name$()) {\n" + " $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n" + "}\n"); } } void StringOneofFieldGenerator:: -GenerateDestructorCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has_$name$()) {\n" - " delete $oneof_prefix$$name$_;\n" - "}\n"); +GenerateMergeFromCodedStream(io::Printer* printer) const { + printer->Print(variables_, + "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n"); + + if (HasUtf8Verification(descriptor_->file()) && + descriptor_->type() == FieldDescriptor::TYPE_STRING) { + printer->Print(variables_, + "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" + " this->$name$().data(), this->$name$().length(),\n" + " ::google::protobuf::internal::WireFormat::PARSE,\n" + " \"$full_name$\");\n"); + } } + // =================================================================== RepeatedStringFieldGenerator:: @@ -566,7 +766,7 @@ GenerateMergingCode(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } void RepeatedStringFieldGenerator:: @@ -586,7 +786,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " this->$name$(this->$name$_size() - 1).data(),\n" " this->$name$(this->$name$_size() - 1).length(),\n" " ::google::protobuf::internal::WireFormat::PARSE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } } @@ -600,7 +800,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" " this->$name$(i).data(), this->$name$(i).length(),\n" " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" @@ -618,7 +818,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { " ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" " this->$name$(i).data(), this->$name$(i).length(),\n" " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$name$\");\n"); + " \"$full_name$\");\n"); } printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 86da38f2..0a5ca440 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -88,6 +88,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; + void GenerateMergeFromCodedStream(io::Printer* printer) const; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index 6b7f8308..4fa3c144 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -35,6 +35,7 @@ // This file tests that various identifiers work as field and type names even // though the same identifiers are used internally by the C++ code generator. +syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default @@ -58,7 +59,7 @@ message TestConflictingSymbolNames { optional int32 total_size = 6; optional int32 tag = 7; - enum TestEnum { FOO = 1; } + enum TestEnum { FOO = 0; } message Data1 { repeated int32 data = 1; } message Data2 { repeated TestEnum data = 1; } message Data3 { repeated string data = 1; } @@ -99,6 +100,8 @@ message TestConflictingSymbolNames { optional uint32 int = 30; optional uint32 friend = 31; optional uint32 class = 37; + optional uint32 typedecl = 39; + optional uint32 auto = 40; // The generator used to #define a macro called "DO" inside the .cc file. message DO {} @@ -116,15 +119,18 @@ message TestConflictingSymbolNames { // names. optional DO release_do = 36; - extensions 1000 to max; -} + // For clashing local variables in Serialize and ByteSize calculation. + optional string target = 38; -message TestConflictingSymbolNamesExtension { - extend TestConflictingSymbolNames { - repeated int32 repeated_int32_ext = 20423638 [packed=true]; - } + extensions 1000 to max; // NO_PROTO3 } +message TestConflictingSymbolNamesExtension { // NO_PROTO3 + extend TestConflictingSymbolNames { // NO_PROTO3 + repeated int32 repeated_int32_ext = 20423638 [packed=true]; // NO_PROTO3 + } // NO_PROTO3 +} // NO_PROTO3 + message DummyMessage {} service TestConflictingMethodNames { diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 93e1c3f1..c509a6a9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -47,6 +47,9 @@ #include <google/protobuf/compiler/cpp/cpp_unittest.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/unittest.pb.h> diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc index e6c446af..678823cd 100644 --- a/src/google/protobuf/compiler/importer.cc +++ b/src/google/protobuf/compiler/importer.cc @@ -44,6 +44,9 @@ #include <algorithm> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/importer.h> diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 8cc5d882..81c636c6 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -34,9 +34,13 @@ #include <google/protobuf/stubs/hash.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/importer.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/testing/file.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/map_util.h> @@ -53,6 +57,10 @@ namespace compiler { namespace { +bool FileExists(const string& path) { + return File::Exists(path); +} + #define EXPECT_SUBSTRING(needle, haystack) \ EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack)) @@ -215,120 +223,6 @@ TEST_F(ImporterTest, RecursiveImport) { error_collector_.text_); } -// TODO(sanjay): The MapField tests below more properly belong in -// descriptor_unittest, but are more convenient to test here. -TEST_F(ImporterTest, MapFieldValid) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Item {\n" - " required string key = 1;\n" - "}\n" - "message Map {\n" - " repeated Item items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - const FileDescriptor* file = importer_.Import("map.proto"); - ASSERT_TRUE(file != NULL) << error_collector_.text_; - EXPECT_EQ("", error_collector_.text_); - - // Check that Map::items points to Item::key - const Descriptor* item_type = file->FindMessageTypeByName("Item"); - ASSERT_TRUE(item_type != NULL); - const Descriptor* map_type = file->FindMessageTypeByName("Map"); - ASSERT_TRUE(map_type != NULL); - const FieldDescriptor* key_field = item_type->FindFieldByName("key"); - ASSERT_TRUE(key_field != NULL); - const FieldDescriptor* items_field = map_type->FindFieldByName("items"); - ASSERT_TRUE(items_field != NULL); - EXPECT_EQ(items_field->experimental_map_key(), key_field); -} - -TEST_F(ImporterTest, MapFieldNotRepeated) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Item {\n" - " required string key = 1;\n" - "}\n" - "message Map {\n" - " required Item items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("only allowed for repeated fields", error()); -} - -TEST_F(ImporterTest, MapFieldNotMessageType) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Map {\n" - " repeated int32 items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("only allowed for fields with a message type", error()); -} - -TEST_F(ImporterTest, MapFieldTypeNotFound) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Map {\n" - " repeated Unknown items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("not defined", error()); -} - -TEST_F(ImporterTest, MapFieldKeyNotFound) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Item {\n" - " required string key = 1;\n" - "}\n" - "message Map {\n" - " repeated Item items = 1 [experimental_map_key = \"badkey\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("Could not find field", error()); -} - -TEST_F(ImporterTest, MapFieldKeyRepeated) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message Item {\n" - " repeated string key = 1;\n" - "}\n" - "message Map {\n" - " repeated Item items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("must not name a repeated field", error()); -} - -TEST_F(ImporterTest, MapFieldKeyNotScalar) { - AddFile( - "map.proto", - "syntax = \"proto2\";\n" - "message ItemKey { }\n" - "message Item {\n" - " required ItemKey key = 1;\n" - "}\n" - "message Map {\n" - " repeated Item items = 1 [experimental_map_key = \"key\"];\n" - "}\n" - ); - EXPECT_TRUE(importer_.Import("map.proto") == NULL); - EXPECT_SUBSTRING("must name a scalar or string", error()); -} - // =================================================================== @@ -339,7 +233,7 @@ class DiskSourceTreeTest : public testing::Test { dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2"); for (int i = 0; i < dirnames_.size(); i++) { - if (File::Exists(dirnames_[i])) { + if (FileExists(dirnames_[i])) { File::DeleteRecursively(dirnames_[i], NULL, NULL); } GOOGLE_CHECK_OK(File::CreateDir(dirnames_[i], 0777)); diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h index 57914450..7f1ce1f9 100644 --- a/src/google/protobuf/compiler/java/java_context.h +++ b/src/google/protobuf/compiler/java/java_context.h @@ -33,6 +33,9 @@ #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 668377a3..0353b607 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -111,6 +111,10 @@ void EnumGenerator::Generate(io::Printer* printer) { "$name$($index$, $number$),\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } + printer->Print( ";\n" "\n"); @@ -141,7 +145,17 @@ void EnumGenerator::Generate(io::Printer* printer) { printer->Print( "\n" - "public final int getNumber() { return value; }\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", @@ -231,11 +245,12 @@ void EnumGenerator::Generate(io::Printer* printer) { "index", SimpleItoa(descriptor_->index())); } printer->Print( - "return $immutable_package$.$descriptor_class$.getDescriptor()\n" + "return $immutable_package$.$descriptor_class$.$descriptor$\n" " .getEnumTypes().get($index$);\n", "immutable_package", FileJavaPackage(descriptor_->file(), true), "descriptor_class", name_resolver_->GetDescriptorClassName(descriptor_->file()), + "descriptor", "getDescriptor()", "index", SimpleItoa(descriptor_->index())); printer->Outdent(); } @@ -283,11 +298,18 @@ void EnumGenerator::Generate(io::Printer* printer) { " if (desc.getType() != getDescriptor()) {\n" " throw new java.lang.IllegalArgumentException(\n" " \"EnumValueDescriptor is not for this type.\");\n" - " }\n" + " }\n", + "classname", descriptor_->name()); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (desc.getIndex() == -1) {\n" + " return UNRECOGNIZED;\n" + " }\n"); + } + printer->Print( " return VALUES[desc.getIndex()];\n" "}\n" - "\n", - "classname", descriptor_->name()); + "\n"); // index is only used for reflection; lite implementation does not need it printer->Print("private final int index;\n"); diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 1f0c4af0..71a2ba4b 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -65,6 +65,8 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["mutable_type"] = name_resolver->GetMutableClassName(descriptor->enum_type()); (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_number"] = SimpleItoa( + descriptor->default_value_enum()->number()); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); @@ -95,7 +97,8 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_builder"] = ""; (*variables)["is_field_present_message"] = - (*variables)["name"] + "_ != " + (*variables)["default"]; + (*variables)["name"] + "_ != " + + (*variables)["default"] + ".getNumber()"; } // For repated builders, one bit is used for whether the array is immutable. @@ -114,6 +117,12 @@ void SetEnumVariables(const FieldDescriptor* descriptor, GenerateGetBitFromLocal(builderBitIndex); (*variables)["set_has_field_bit_to_local"] = GenerateSetBitToLocal(messageBitIndex); + + if (SupportUnknownEnumValue(descriptor->file())) { + (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED"; + } else { + (*variables)["unknown"] = (*variables)["default"]; + } } } // namespace @@ -150,6 +159,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$boolean has$capitalized_name$();\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value();\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); @@ -158,7 +172,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_;\n"); + "private int $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); @@ -167,17 +181,25 @@ GenerateMembers(io::Printer* printer) const { " return $get_has_field_bit_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return $name$_;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " $type$ result = $type$.valueOf($name$_);\n" + " return result == null ? $unknown$ : result;\n" "}\n"); } void ImmutableEnumFieldGenerator:: GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, - "private $type$ $name$_ = $default$;\n"); + "private int $name$_ = $default_number$;\n"); if (SupportFieldPresence(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -185,10 +207,25 @@ GenerateBuilderMembers(io::Printer* printer) const { " return $get_has_field_bit_builder$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" + " $name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " $type$ result = $type$.valueOf($name$_);\n" + " return result == null ? $unknown$ : result;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -197,7 +234,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " $set_has_field_bit_builder$\n" - " $name$_ = value;\n" + " $name$_ = value.getNumber();\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -205,7 +242,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder clear$capitalized_name$() {\n" " $clear_has_field_bit_builder$\n" - " $name$_ = $default$;\n" + " $name$_ = $default_number$;\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -218,13 +255,13 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: GenerateInitializationCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); + printer->Print(variables_, "$name$_ = $default_number$;\n"); } void ImmutableEnumFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_ = $default$;\n" + "$name$_ = $default_number$;\n" "$clear_has_field_bit_builder$\n"); } @@ -235,11 +272,13 @@ GenerateMergingCode(io::Printer* printer) const { "if (other.has$capitalized_name$()) {\n" " set$capitalized_name$(other.get$capitalized_name$());\n" "}\n"); - } else { + } else if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "if (other.get$capitalized_name$() != $default$) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" + "if (other.$name$_ != $default_number$) {\n" + " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" "}\n"); + } else { + GOOGLE_LOG(FATAL) << "Can't reach here."; } } @@ -257,23 +296,26 @@ GenerateBuildingCode(io::Printer* printer) const { void ImmutableEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" - "if (value == null) {\n"); - if (UseUnknownFieldSet(descriptor_->containing_type())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$set_has_field_bit_message$\n" + "$name$_ = rawValue;\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_has_field_bit_message$\n" + " $name$_ = rawValue;\n" + "}\n"); } - printer->Print(variables_, - "} else {\n" - " $set_has_field_bit_message$\n" - " $name$_ = value;\n" - "}\n"); } void ImmutableEnumFieldGenerator:: @@ -285,7 +327,7 @@ void ImmutableEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeEnum($number$, $name$_.getNumber());\n" + " output.writeEnum($number$, $name$_);\n" "}\n"); } @@ -294,23 +336,21 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSize($number$, $name$_.getNumber());\n" + " .computeEnumSize($number$, $name$_);\n" "}\n"); } void ImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, - "result = result &&\n" - " (get$capitalized_name$() == other.get$capitalized_name$());\n"); + "result = result && $name$_ == other.$name$_;\n"); } void ImmutableEnumFieldGenerator:: GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "hash = (37 * hash) + $constant_name$;\n" - "hash = (53 * hash) + com.google.protobuf.Internal.hashEnum(\n" - " get$capitalized_name$());\n"); + "hash = (53 * hash) + $name$_;\n"); } string ImmutableEnumFieldGenerator::GetBoxedType() const { @@ -344,11 +384,22 @@ GenerateMembers(io::Printer* printer) const { " return $has_oneof_case_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " if ($has_oneof_case_message$) {\n" + " return (java.lang.Integer) $oneof_name$_;\n" + " }\n" + " return $default_number$;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " return ($type$) $oneof_name$_;\n" + " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" "}\n"); @@ -363,11 +414,30 @@ GenerateBuilderMembers(io::Printer* printer) const { " return $has_oneof_case_message$;\n" "}\n"); } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " if ($has_oneof_case_message$) {\n" + " return ((java.lang.Integer) $oneof_name$_).intValue();\n" + " }\n" + " return $default_number$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + } WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " return ($type$) $oneof_name$_;\n" + " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" "}\n"); @@ -378,7 +448,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" + " $oneof_name$_ = value.getNumber();\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -404,36 +474,44 @@ GenerateBuildingCode(io::Printer* printer) const { void ImmutableEnumOneofFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); + } else { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); + } } void ImmutableEnumOneofFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" - "if (value == null) {\n"); - if (UseUnknownFieldSet(descriptor_->containing_type())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = rawValue;\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = rawValue;\n" + "}\n"); } - printer->Print(variables_, - "} else {\n" - " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" - "}\n"); } void ImmutableEnumOneofFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeEnum($number$, (($type$) $oneof_name$_).getNumber());\n" + " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n" "}\n"); } @@ -442,10 +520,36 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSize($number$, (($type$) $oneof_name$_).getNumber());\n" + " .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n" "}\n"); } +void ImmutableEnumOneofFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "result = result && get$capitalized_name$Value()\n" + " == other.get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); + } +} + +void ImmutableEnumOneofFieldGenerator:: +GenerateHashCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().getNumber();\n"); + } +} + // =================================================================== RepeatedImmutableEnumFieldGenerator:: @@ -482,17 +586,36 @@ GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$(int index);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value(int index);\n"); + } } void RepeatedImmutableEnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.util.List<$type$> $name$_;\n"); + "private java.util.List<java.lang.Integer> $name$_;\n" + "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$> $name$_converter_ =\n" + " new com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$>() {\n" + " public $type$ convert(java.lang.Integer from) {\n" + " $type$ result = $type$.valueOf(from);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " };\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" - " return $name$_;\n" // note: unmodifiable list + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -502,8 +625,21 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" + " return $name$_converter_.convert($name$_.get(index));\n" "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + } if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->containing_type())) { @@ -524,12 +660,12 @@ GenerateBuilderMembers(io::Printer* printer) const { // memory allocations. Note, immutable is a strong guarantee here -- not // just that the list cannot be modified via the reference but that the // list can never be modified. - "private java.util.List<$type$> $name$_ =\n" + "private java.util.List<java.lang.Integer> $name$_ =\n" " java.util.Collections.emptyList();\n" "private void ensure$capitalized_name$IsMutable() {\n" " if (!$get_mutable_bit_builder$) {\n" - " $name$_ = new java.util.ArrayList<$type$>($name$_);\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n" " $set_mutable_bit_builder$;\n" " }\n" "}\n"); @@ -541,7 +677,8 @@ GenerateBuilderMembers(io::Printer* printer) const { // has been built, thus mutating the message which is supposed to be // immutable. "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" - " return java.util.Collections.unmodifiableList($name$_);\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -551,7 +688,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" + " return $name$_converter_.convert($name$_.get(index));\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -561,7 +698,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.set(index, value);\n" + " $name$_.set(index, value.getNumber());\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -572,7 +709,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " throw new NullPointerException();\n" " }\n" " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.add(value.getNumber());\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -581,8 +718,9 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public Builder addAll$capitalized_name$(\n" " java.lang.Iterable<? extends $type$> values) {\n" " ensure$capitalized_name$IsMutable();\n" - " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" - " values, $name$_);\n" + " for ($type$ value : values) {\n" + " $name$_.add(value.getNumber());\n" + " }\n" " $on_changed$\n" " return this;\n" "}\n"); @@ -594,6 +732,48 @@ GenerateBuilderMembers(io::Printer* printer) const { " $on_changed$\n" " return this;\n" "}\n"); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<java.lang.Integer>\n" + "get$capitalized_name$ValueList() {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(\n" + " int index, int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$Value(int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$Value(\n" + " java.lang.Iterable<java.lang.Integer> values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (int value : values) {\n" + " $name$_.add(value);\n" + " }\n" + " $on_changed$\n" + " return this;\n" + "}\n"); + } } void RepeatedImmutableEnumFieldGenerator:: @@ -648,26 +828,32 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { // Read and store the enum - printer->Print(variables_, - "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" - "if (value == null) {\n"); - if (UseUnknownFieldSet(descriptor_->containing_type())) { + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - " unknownFields.mergeVarintField($number$, rawValue);\n"); + "int rawValue = input.readEnum();\n" + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + "}\n" + "$name$_.add(rawValue);\n"); } else { printer->Print(variables_, - " unknownFieldsCodedOutput.writeRawVarint32(tag);\n" - " unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n"); + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " if (!$get_mutable_bit_parser$) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " $set_mutable_bit_parser$;\n" + " }\n" + " $name$_.add(rawValue);\n" + "}\n"); } - printer->Print(variables_, - " } else {\n" - " if (!$get_mutable_bit_parser$) {\n" - " $name$_ = new java.util.ArrayList<$type$>();\n" - " $set_mutable_bit_parser$;\n" - " }\n" - " $name$_.add(value);\n" - "}\n"); } void RepeatedImmutableEnumFieldGenerator:: @@ -705,12 +891,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnumNoTag($name$_.get(i).getNumber());\n" + " output.writeEnumNoTag($name$_.get(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeEnum($number$, $name$_.get(i).getNumber());\n" + " output.writeEnum($number$, $name$_.get(i));\n" "}\n"); } } @@ -725,7 +911,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeEnumSizeNoTag($name$_.get(i).getNumber());\n" + " .computeEnumSizeNoTag($name$_.get(i));\n" "}\n"); printer->Print( "size += dataSize;\n"); @@ -754,8 +940,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, - "result = result && get$capitalized_name$List()\n" - " .equals(other.get$capitalized_name$List());\n"); + "result = result && $name$_.equals(other.$name$_);\n"); } void RepeatedImmutableEnumFieldGenerator:: @@ -763,8 +948,7 @@ GenerateHashCode(io::Printer* printer) const { printer->Print(variables_, "if (get$capitalized_name$Count() > 0) {\n" " hash = (37 * hash) + $constant_name$;\n" - " hash = (53 * hash) + com.google.protobuf.Internal.hashEnumList(\n" - " get$capitalized_name$List());\n" + " hash = (53 * hash) + $name$_.hashCode();\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 6a9535aa..b8ff7343 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -106,6 +106,8 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator { void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator); diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index d7b0f3fc..49635bb4 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -35,12 +35,16 @@ #include <google/protobuf/compiler/java/java_field.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum_field.h> #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_lazy_message_field.h> +#include <google/protobuf/compiler/java/java_map_field.h> #include <google/protobuf/compiler/java/java_message_field.h> #include <google/protobuf/compiler/java/java_primitive_field.h> #include <google/protobuf/compiler/java/java_string_field.h> @@ -48,6 +52,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -61,12 +66,17 @@ ImmutableFieldGenerator* MakeImmutableGenerator( if (field->is_repeated()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { - return new RepeatedImmutableLazyMessageFieldGenerator( + if (IsMapEntry(field->message_type())) { + return new ImmutableMapFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { - return new RepeatedImmutableMessageFieldGenerator( - field, messageBitIndex, builderBitIndex, context); + if (IsLazy(field)) { + return new RepeatedImmutableLazyMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new RepeatedImmutableMessageFieldGenerator( + field, messageBitIndex, builderBitIndex, context); + } } case JAVATYPE_ENUM: return new RepeatedImmutableEnumFieldGenerator( diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index db339d5b..5bc5634e 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -37,6 +37,9 @@ #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 231b1445..1ac945cd 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -35,6 +35,9 @@ #include <google/protobuf/compiler/java/java_file.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum.h> @@ -180,29 +183,6 @@ bool FileGenerator::Validate(string* error) { "option to specify a different outer class name for the .proto file."); return false; } - // If java_outer_classname option is not set and the default outer class name - // conflicts with a type defined in the message, we will append a suffix to - // avoid the conflict. This allows proto1 API protos to be dual-compiled into - // proto2 API without code change. When this happens we'd like to issue an - // warning to let the user know that the outer class name has been changed. - // Although we only do this automatic naming fix for immutable API, mutable - // outer class name will also be affected as it's contructed from immutable - // outer class name with an additional "Mutable" prefix. Since the naming - // change in mutable API is not caused by a naming conflict, we generate the - // warning for immutable API only. - if (immutable_api_ && !file_->options().has_java_outer_classname()) { - string default_classname = - name_resolver_->GetFileDefaultImmutableClassName(file_); - if (default_classname != classname_) { - GOOGLE_LOG(WARNING) << file_->name() << ": The default outer class name, \"" - << default_classname << "\", conflicts with a type " - << "declared in the proto file and an alternative outer " - << "class name is used: \"" << classname_ << "\". To avoid " - << "this warning, please use the java_outer_classname " - << "option to specify a different outer class name for " - << "the .proto file."; - } - } return true; } @@ -323,6 +303,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( SharedCodeGenerator shared_code_generator(file_); shared_code_generator.GenerateDescriptors(printer); + for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->GenerateStaticVariableInitializers(printer); } diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index c805b9a6..0b2230a0 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index c3a47e3e..a743ce22 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -35,6 +35,9 @@ #include <google/protobuf/compiler/java/java_generator.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_file.h> #include <google/protobuf/compiler/java/java_generator_factory.h> @@ -99,10 +102,14 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector<string> all_files; + vector<FileGenerator*> file_generators; if (generate_immutable_code) { file_generators.push_back(new FileGenerator(file, /* immutable = */ true)); } + if (generate_mutable_code) { + file_generators.push_back(new FileGenerator(file, /* mutable = */ false)); + } for (int i = 0; i < file_generators.size(); ++i) { if (!file_generators[i]->Validate(error)) { for (int j = 0; j < file_generators.size(); ++j) { diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 3efd7edb..23685385 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -306,6 +306,26 @@ JavaType GetJavaType(const FieldDescriptor* field) { return JAVATYPE_INT; } +const char* PrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "int"; + case JAVATYPE_LONG : return "long"; + case JAVATYPE_FLOAT : return "float"; + case JAVATYPE_DOUBLE : return "double"; + case JAVATYPE_BOOLEAN: return "boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; + case JAVATYPE_ENUM : return NULL; + case JAVATYPE_MESSAGE: return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + const char* BoxedPrimitiveTypeName(JavaType type) { switch (type) { case JAVATYPE_INT : return "java.lang.Integer"; diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 93f23a93..2707fa0a 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -149,6 +149,8 @@ enum JavaType { JavaType GetJavaType(const FieldDescriptor* field); +const char* PrimitiveTypeName(JavaType type); + // Get the fully-qualified class name for a boxed primitive type, e.g. // "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message // types. @@ -168,13 +170,6 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field, } bool IsDefaultValueJavaDefault(const FieldDescriptor* field); -// Does this message class use UnknownFieldSet? -// Otherwise, unknown fields will be stored in a ByteString object -inline bool UseUnknownFieldSet(const Descriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; -} - // Does this message class have generated parsing, serialization, and other // standard methods for which reflection-based fallback implementations exist? inline bool HasGeneratedMethods(const Descriptor* descriptor) { @@ -308,12 +303,27 @@ bool HasRequiredFields(const Descriptor* descriptor); // Whether a .proto file supports field presence test for non-message types. inline bool SupportFieldPresence(const FileDescriptor* descriptor) { - return true; + return descriptor->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet +// but in the message and can be queried using additional getters that return +// ints. +inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) { + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; } // Check whether a mesasge has repeated fields. bool HasRepeatedFields(const Descriptor* descriptor); +inline bool IsMapEntry(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +inline bool PreserveUnknownFields(const Descriptor* descriptor) { + return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + } // 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 new file mode 100644 index 00000000..2986f51f --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -0,0 +1,455 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/compiler/java/java_map_field.h> + +#include <google/protobuf/compiler/java/java_context.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> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + +string TypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver, + bool boxed) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return boxed ? BoxedPrimitiveTypeName(GetJavaType(field)) + : PrimitiveTypeName(GetJavaType(field)); + } +} + +string WireType(const FieldDescriptor* field) { + return "com.google.protobuf.WireFormat.FieldType." + + string(FieldTypeName(field->type())); +} + +void SetMessageVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map<string, string>* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); + (*variables)["key_type"] = TypeName(key, name_resolver, false); + (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true); + (*variables)["key_wire_type"] = WireType(key); + (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); + if (GetJavaType(value) == JAVATYPE_ENUM) { + // We store enums as Integers internally. + (*variables)["value_type"] = "int"; + (*variables)["boxed_value_type"] = "java.lang.Integer"; + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver) + ".getNumber()"; + + (*variables)["value_enum_type"] = TypeName(value, name_resolver, false); + + if (SupportUnknownEnumValue(descriptor->file())) { + // Map unknown values to a special UNRECOGNIZED value if supported. + (*variables)["unrecognized_value"] = + (*variables)["value_enum_type"] + ".UNRECOGNIZED"; + } else { + // Map unknown values to the default value if we don't have UNRECOGNIZED. + (*variables)["unrecognized_value"] = + DefaultValue(value, true, name_resolver); + } + } else { + (*variables)["value_type"] = TypeName(value, name_resolver, false); + (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true); + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver); + } + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + // For repeated fields, one bit is used for whether the array is immutable + // in the parsing constructor. + (*variables)["get_mutable_bit_parser"] = + GenerateGetBitMutableLocal(builderBitIndex); + (*variables)["set_mutable_bit_parser"] = + GenerateSetBitMutableLocal(builderBitIndex); + + if (HasDescriptorMethods(descriptor->file())) { + (*variables)["lite"] = ""; + (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry"; + (*variables)["descriptor"] = + name_resolver->GetImmutableClassName(descriptor->file()) + + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + + "_descriptor, "; + } else { + (*variables)["lite"] = "Lite"; + (*variables)["map_field_parameter"] = ""; + (*variables)["descriptor"] = ""; + } +} + +} // namespace + +ImmutableMapFieldGenerator:: +ImmutableMapFieldGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMapFieldGenerator:: +~ImmutableMapFieldGenerator() {} + +int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { + return 0; +} + +int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const { + return 1; +} + +void ImmutableMapFieldGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$();\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$Value();\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$();\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private static final com.google.protobuf.MapEntry$lite$<\n" + " $type_parameters$> $name$DefaultEntry =\n" + " com.google.protobuf.MapEntry$lite$\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $descriptor$\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n"); + printer->Print( + variables_, + "private com.google.protobuf.MapField$lite$<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapField$lite$.emptyMapField(\n" + " $map_field_parameter$);\n" + "\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "private static final\n" + "com.google.protobuf.Internal.MapAdapter.Converter<\n" + " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n" + " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n" + " $value_enum_type$.internalGetValueMap(),\n" + " $unrecognized_value$);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return $name$_.getMap();\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMap(), $name$ValueConverter);\n" + "}\n"); + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return $name$_.getMap();\n" + "}\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private com.google.protobuf.MapField$lite$<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapField$lite$.newMapField(\n" + " $map_field_parameter$);\n" + "\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMap(), $name$ValueConverter);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "getMutable$capitalized_name$() {\n" + " $on_changed$\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " $name$_.getMutableMap(), $name$ValueConverter);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return $name$_.getMap();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "getMutable$capitalized_name$Value() {\n" + " $on_changed$\n" + " return $name$_.getMutableMap();\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return $name$_.getMap();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$>\n" + "getMutable$capitalized_name$() {\n" + " $on_changed$\n" + " return $name$_.getMutableMap();\n" + "}\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldGenerator:: +GenerateBuilderClearCode(io::Printer* printer) const { + printer->Print( + variables_, + "$name$_.clear();\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print( + variables_, + "$name$_.mergeFrom(other.$name$_);\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + printer->Print( + variables_, + // We do a copy of the map field to ensure that the built result is + // immutable. Implementation of this copy() method can do copy-on-write + // to defer this copy until further modifications are made on the field. + "result.$name$_ = $name$_.copy();\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!$get_mutable_bit_parser$) {\n" + " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n" + " $map_field_parameter$);\n" + " $set_mutable_bit_parser$;\n" + "}\n"); + if (!SupportUnknownEnumValue(descriptor_->file()) && + GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "com.google.protobuf.ByteString bytes = input.readBytes();\n" + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n"); + printer->Print( + variables_, + "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" + "} else {\n" + " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" + "}\n"); + } else { + printer->Print( + variables_, + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = input.readMessage(\n" + " $name$DefaultEntry.getParserForType(), extensionRegistry);\n" + "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"); + } +} + +void ImmutableMapFieldGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // Nothing to do here. +} + +void ImmutableMapFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : $name$_.getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " output.writeMessage($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : $name$_.getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeMessageSize($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print( + variables_, + "result = result && $name$_.equals(other.$name$_);\n"); +} + +void ImmutableMapFieldGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!$name$_.getMap().isEmpty()) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + $name$_.hashCode();\n" + "}\n"); +} + +string ImmutableMapFieldGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h new file mode 100644 index 00000000..80a94f45 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ + +#include <google/protobuf/compiler/java/java_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMapFieldGenerator : public ImmutableFieldGenerator { + public: + explicit ImmutableMapFieldGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMapFieldGenerator(); + + // implements ImmutableFieldGenerator --------------------------------------- + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateBuilderClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__ diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 8aa89ac7..dd1ad6a6 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -38,6 +38,9 @@ #include <google/protobuf/stubs/hash.h> #include <map> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <google/protobuf/compiler/java/java_context.h> @@ -264,60 +267,36 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { descriptor_->containing_type() == NULL && MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); + map<string, string> variables; + variables["static"] = is_own_file ? " " : " static "; + variables["classname"] = descriptor_->name(); + variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); + variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite"; + WriteMessageDocComment(printer, descriptor_); // The builder_type stores the super type name of the nested Builder class. string builder_type; if (descriptor_->extension_range_count() > 0) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n" - " $classname$> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "static", is_own_file ? " " : " static ", - "classname", descriptor_->name(), - "extra_interfaces", ExtraMessageInterfaces(descriptor_)); - builder_type = strings::Substitute( - "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>", - name_resolver_->GetImmutableClassName(descriptor_)); - } else { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" - " $classname$> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "static", is_own_file ? " " : " static ", - "classname", descriptor_->name(), - "extra_interfaces", ExtraMessageInterfaces(descriptor_)); - builder_type = strings::Substitute( - "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>", - name_resolver_->GetImmutableClassName(descriptor_)); - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage<\n" + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_), + variables["lite"]); } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "static", is_own_file ? " " : " static ", - "classname", descriptor_->name(), - "extra_interfaces", ExtraMessageInterfaces(descriptor_)); - builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>"; - } else { - printer->Print( - "public$static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "static", is_own_file ? " " : " static ", - "classname", descriptor_->name(), - "extra_interfaces", ExtraMessageInterfaces(descriptor_)); - builder_type = "com.google.protobuf.GeneratedMessageLite.Builder"; - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage$lite$ implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessage$0.Builder", + variables["lite"]); } printer->Indent(); // Using builder_type, instead of Builder, prevents the Builder class from @@ -328,16 +307,22 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "// Use $classname$.newBuilder() to construct.\n" "private $classname$($buildertype$ builder) {\n" " super(builder);\n" - "$set_unknown_fields$\n" "}\n", "classname", descriptor_->name(), - "buildertype", builder_type, - "set_unknown_fields", - " this.unknownFields = builder.getUnknownFields();"); + "buildertype", builder_type); printer->Print( - // Used when constructing the default instance, which cannot be initialized - // immediately because it may cyclically refer to other default instances. - "private $classname$(boolean noInit) {$set_default_unknown_fields$}\n" + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } + printer->Outdent(); + printer->Print( + "}\n" "\n" "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" @@ -349,23 +334,22 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "}\n" "\n", "classname", descriptor_->name(), - "set_default_unknown_fields", UseUnknownFieldSet(descriptor_) - ? " this.unknownFields =" - " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); " - : " this.unknownFields = com.google.protobuf.ByteString.EMPTY;"); + "lite", variables["lite"]); - if (UseUnknownFieldSet(descriptor_)) { + if (HasDescriptorMethods(descriptor_)) { printer->Print( - "private final com.google.protobuf.UnknownFieldSet unknownFields;\n" - "" - "@java.lang.Override\n" - "public final com.google.protobuf.UnknownFieldSet\n" - " getUnknownFields() {\n" - " return this.unknownFields;\n" - "}\n"); - } else { + "@java.lang.Override\n" + "public final com.google.protobuf.UnknownFieldSet\n" + "getUnknownFields() {\n"); + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + " return this.unknownFields;\n"); + } else { + printer->Print( + " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n"); + } printer->Print( - "private final com.google.protobuf.ByteString unknownFields;\n"); + "}\n"); } if (HasGeneratedMethods(descriptor_)) { @@ -382,6 +366,8 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { } for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate Java classes for map entry messages. + if (IsMapEntry(descriptor_->nested_type(i))) continue; ImmutableMessageGenerator messageGenerator( descriptor_->nested_type(i), context_); messageGenerator.GenerateInterface(printer); @@ -480,20 +466,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - // Called by the constructor, except in the case of the default instance, - // in which case this is called by static init code later on. - printer->Print("private void initFields() {\n"); - printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateInitializationCode(printer); - } - } - - printer->Outdent(); - printer->Print("}\n"); - if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer, MEMOIZE); GenerateMessageSerializationMethods(printer); @@ -512,8 +484,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print( "\n" "static {\n" - " defaultInstance = new $classname$(true);\n" - " defaultInstance.initFields();\n" + " defaultInstance = new $classname$();\n" "}\n" "\n" "// @@protoc_insertion_point(class_scope:$full_name$)\n", @@ -593,17 +564,15 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (UseUnknownFieldSet(descriptor_)) { - if (descriptor_->options().message_set_wire_format()) { + if (PreserveUnknownFields(descriptor_)) { + if (descriptor_->options().message_set_wire_format() + && HasDescriptorMethods(descriptor_)) { printer->Print( - "getUnknownFields().writeAsMessageSetTo(output);\n"); + "unknownFields.writeAsMessageSetTo(output);\n"); } else { printer->Print( - "getUnknownFields().writeTo(output);\n"); + "unknownFields.writeTo(output);\n"); } - } else { - printer->Print( - "output.writeRawBytes(unknownFields);\n"); } printer->Outdent(); @@ -632,17 +601,15 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } } - if (UseUnknownFieldSet(descriptor_)) { - if (descriptor_->options().message_set_wire_format()) { + if (PreserveUnknownFields(descriptor_)) { + if (descriptor_->options().message_set_wire_format() + && HasDescriptorMethods(descriptor_)) { printer->Print( - "size += getUnknownFields().getSerializedSizeAsMessageSet();\n"); + "size += unknownFields.getSerializedSizeAsMessageSet();\n"); } else { printer->Print( - "size += getUnknownFields().getSerializedSize();\n"); + "size += unknownFields.getSerializedSize();\n"); } - } else { - printer->Print( - "size += unknownFields.size();\n"); } printer->Outdent(); @@ -653,13 +620,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { "\n"); printer->Print( - "private static final long serialVersionUID = 0L;\n" - "@java.lang.Override\n" - "protected java.lang.Object writeReplace()\n" - " throws java.io.ObjectStreamException {\n" - " return super.writeReplace();\n" - "}\n" - "\n"); + "private static final long serialVersionUID = 0L;\n"); } void ImmutableMessageGenerator:: @@ -740,7 +701,7 @@ void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange( void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { printer->Print( - "public static Builder newBuilder() { return Builder.create(); }\n" + "public static Builder newBuilder() { return new Builder(); }\n" "public Builder newBuilderForType() { return newBuilder(); }\n" "public static Builder newBuilder($classname$ prototype) {\n" " return newBuilder().mergeFrom(prototype);\n" @@ -809,7 +770,6 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer, DONT_MEMOIZE); - GenerateBuilderParsingMethods(printer); } // oneof @@ -864,6 +824,20 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { .GenerateBuilderMembers(printer); } + if (!PreserveUnknownFields(descriptor_)) { + printer->Print( + "public final Builder setUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n" + "public final Builder mergeUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n"); + } + printer->Print( "\n" "// @@protoc_insertion_point(builder_scope:$full_name$)\n", @@ -886,6 +860,41 @@ GenerateDescriptorMethods(io::Printer* printer) { "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } + vector<const FieldDescriptor*> map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } + } + if (!map_fields.empty()) { + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return $name$_;\n", + "number", SimpleItoa(field->number()), + "name", info->name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + } printer->Print( "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" " internalGetFieldAccessorTable() {\n" @@ -949,13 +958,8 @@ GenerateCommonBuilderMethods(io::Printer* printer) { } printer->Print( - "private static Builder create() {\n" - " return new Builder();\n" - "}\n" - "\n" "public Builder clear() {\n" - " super.clear();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + " super.clear();\n"); printer->Indent(); @@ -979,12 +983,8 @@ GenerateCommonBuilderMethods(io::Printer* printer) { printer->Print( " return this;\n" "}\n" - "\n" - "public Builder clone() {\n" - " return create().mergeFrom(buildPartial());\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + "\n"); + if (HasDescriptorMethods(descriptor_)) { printer->Print( "public com.google.protobuf.Descriptors.Descriptor\n" @@ -1153,13 +1153,13 @@ GenerateCommonBuilderMethods(io::Printer* printer) { " this.mergeExtensionFields(other);\n"); } - if (UseUnknownFieldSet(descriptor_)) { + if (PreserveUnknownFields(descriptor_)) { printer->Print( - " this.mergeUnknownFields(other.getUnknownFields());\n"); - } else { - printer->Print( - " setUnknownFields(\n" - " getUnknownFields().concat(other.unknownFields));\n"); + " this.mergeUnknownFields(other.unknownFields);\n"); + } + + if (HasDescriptorMethods(descriptor_)) { + printer->Print(" onChanged();\n"); } printer->Print( @@ -1171,31 +1171,6 @@ GenerateCommonBuilderMethods(io::Printer* printer) { // =================================================================== -void ImmutableMessageGenerator:: -GenerateBuilderParsingMethods(io::Printer* printer) { - printer->Print( - "public Builder mergeFrom(\n" - " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" - " throws java.io.IOException {\n" - " $classname$ parsedMessage = null;\n" - " try {\n" - " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" - " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" - " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" - " throw e;\n" - " } finally {\n" - " if (parsedMessage != null) {\n" - " mergeFrom(parsedMessage);\n" - " }\n" - " }\n" - " return this;\n" - "}\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); -} - -// =================================================================== - void ImmutableMessageGenerator::GenerateIsInitialized( io::Printer* printer, UseMemoization useMemoization) { bool memoization = useMemoization == MEMOIZE; @@ -1256,15 +1231,26 @@ void ImmutableMessageGenerator::GenerateIsInitialized( "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; case FieldDescriptor::LABEL_OPTIONAL: + if (!SupportFieldPresence(descriptor_->file()) && + field->containing_oneof() != NULL) { + const OneofDescriptor* oneof = field->containing_oneof(); + const OneofGeneratorInfo* oneof_info = + context_->GetOneofGeneratorInfo(oneof); + printer->Print( + "if ($oneof_name$Case_ == $field_number$) {\n", + "oneof_name", oneof_info->name, + "field_number", SimpleItoa(field->number())); + } else { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + } printer->Print( - "if (has$name$()) {\n" " if (!get$name$().isInitialized()) {\n" " $memoize$\n" " return false;\n" " }\n" "}\n", - "type", name_resolver_->GetImmutableClassName( - field->message_type()), "name", info->capitalized_name, "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); break; @@ -1358,10 +1344,14 @@ GenerateEqualsAndHashCode(io::Printer* printer) { "}\n"); } } - if (HasDescriptorMethods(descriptor_)) { + 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 + // the best we can do. printer->Print( - "result = result &&\n" - " getUnknownFields().equals(other.getUnknownFields());\n"); + "result = result && unknownFields.equals(other.unknownFields);\n"); + } + if (HasDescriptorMethods(descriptor_)) { if (descriptor_->extension_range_count() > 0) { printer->Print( "result = result &&\n" @@ -1421,13 +1411,8 @@ GenerateEqualsAndHashCode(io::Printer* printer) { } } - if (UseUnknownFieldSet(descriptor_)) { - printer->Print( - "hash = (29 * hash) + getUnknownFields().hashCode();\n"); - } else { - printer->Print( - "hash = (29 * hash) + unknownFields.hashCode();\n"); - } + printer->Print( + "hash = (29 * hash) + unknownFields.hashCode();\n"); printer->Print( "memoizedHashCode = hash;\n" "return hash;\n"); @@ -1468,7 +1453,7 @@ GenerateParsingConstructor(io::Printer* printer) { // Initialize all fields to default. printer->Print( - "initFields();\n"); + "this();\n"); // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; @@ -1483,17 +1468,16 @@ GenerateParsingConstructor(io::Printer* printer) { "bit_field_name", GetBitFieldName(i)); } - if (UseUnknownFieldSet(descriptor_)) { - printer->Print( - "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" - " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); - } else { - printer->Print( - "com.google.protobuf.ByteString.Output unknownFieldsOutput =\n" - " com.google.protobuf.ByteString.newOutput();\n" - "com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput =\n" - " com.google.protobuf.CodedOutputStream.newInstance(\n" - " unknownFieldsOutput);\n"); + if (PreserveUnknownFields(descriptor_)) { + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); + } else { + printer->Print( + "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n"); + } } printer->Print( @@ -1513,16 +1497,41 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Print( "case 0:\n" // zero signals EOF / limit reached " done = true;\n" - " break;\n" - "default: {\n" - " if (!parseUnknownField(input,$unknown_fields$\n" - " extensionRegistry, tag)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n", - "unknown_fields", UseUnknownFieldSet(descriptor_) - ? " unknownFields," : " unknownFieldsCodedOutput,"); + " break;\n"); + + if (PreserveUnknownFields(descriptor_)) { + if (!HasDescriptorMethods(descriptor_) + && descriptor_->extension_range_count() > 0) { + // Lite runtime directly invokes parseUnknownField to reduce method + // counts. + printer->Print( + "default: {\n" + " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" + " input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } else { + printer->Print( + "default: {\n" + " if (!parseUnknownField(input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } + } else { + printer->Print( + "default: {\n" + " if (!input.skipField(tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; @@ -1582,19 +1591,9 @@ GenerateParsingConstructor(io::Printer* printer) { field_generators_.get(field).GenerateParsingDoneCode(printer); } - // Make unknown fields immutable. - if (UseUnknownFieldSet(descriptor_)) { - printer->Print( - "this.unknownFields = unknownFields.build();\n"); - } else { - printer->Print( - "try {\n" - " unknownFieldsCodedOutput.flush();\n" - "} catch (java.io.IOException e) {\n" - "// Should not happen\n" - "} finally {\n" - " unknownFields = unknownFieldsOutput.toByteString();\n" - "}\n"); + if (PreserveUnknownFields(descriptor_)) { + // Make unknown fields immutable. + printer->Print("this.unknownFields = unknownFields.build();\n"); } // Make extensions immutable. @@ -1611,7 +1610,7 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static com.google.protobuf.Parser<$classname$> PARSER =\n" + "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" " new com.google.protobuf.AbstractParser<$classname$>() {\n", "classname", descriptor_->name()); printer->Indent(); diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index fece1c21..2703016e 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -118,7 +118,6 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateBuilder(io::Printer* printer); void GenerateCommonBuilderMethods(io::Printer* printer); void GenerateDescriptorMethods(io::Printer* printer); - void GenerateBuilderParsingMethods(io::Printer* printer); void GenerateIsInitialized(io::Printer* printer, UseMemoization useMemoization); void GenerateEqualsAndHashCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index e681314e..538f1248 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -179,7 +179,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " return $name$_;\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); if (HasNestedBuilders(descriptor_->containing_type())) { @@ -187,7 +187,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$OrBuilder " "get$capitalized_name$OrBuilder() {\n" - " return $name$_;\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); } } else { @@ -257,14 +257,8 @@ GenerateBuilderMembers(io::Printer* printer) const { bool support_field_presence = SupportFieldPresence(descriptor_->file()); - if (support_field_presence) { - printer->Print(variables_, - // Used when the builder is null. - "private $type$ $name$_ = $type$.getDefaultInstance();\n"); - } else { - printer->Print(variables_, - "private $type$ $name$_ = null;\n"); - } + printer->Print(variables_, + "private $type$ $name$_ = null;\n"); if (HasNestedBuilders(descriptor_->containing_type())) { printer->Print(variables_, @@ -296,13 +290,8 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); PrintNestedBuilderFunction(printer, "$deprecation$public $type$ get$capitalized_name$()", - - support_field_presence - ? "return $name$_;\n" - : "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", - + "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n", "return $name$Builder_.getMessage();\n", - NULL); // Field.Builder setField(Field value) @@ -342,6 +331,7 @@ GenerateBuilderMembers(io::Printer* printer) const { support_field_presence ? "if ($get_has_field_bit_builder$ &&\n" + " $name$_ != null &&\n" " $name$_ != $type$.getDefaultInstance()) {\n" " $name$_ =\n" " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" @@ -367,11 +357,8 @@ GenerateBuilderMembers(io::Printer* printer) const { PrintNestedBuilderFunction(printer, "$deprecation$public Builder clear$capitalized_name$()", - support_field_presence - ? "$name$_ = $type$.getDefaultInstance();\n" - "$on_changed$\n" - : "$name$_ = null;\n" - "$on_changed$\n", + "$name$_ = null;\n" + "$on_changed$\n", support_field_presence ? "$name$Builder_.clear();\n" @@ -394,16 +381,9 @@ GenerateBuilderMembers(io::Printer* printer) const { "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" " if ($name$Builder_ != null) {\n" " return $name$Builder_.getMessageOrBuilder();\n" - " } else {\n"); - if (support_field_presence) { - printer->Print(variables_, - " return $name$_;\n"); - } else { - printer->Print(variables_, - " return $name$_ == null ?\n" - " $type$.getDefaultInstance() : $name$_;\n"); - } - printer->Print(variables_, + " } else {\n" + " return $name$_ == null ?\n" + " $type$.getDefaultInstance() : $name$_;\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -434,17 +414,13 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const { void ImmutableMessageFieldGenerator:: -GenerateInitializationCode(io::Printer* printer) const { - if (SupportFieldPresence(descriptor_->file())) { - printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); - } -} +GenerateInitializationCode(io::Printer* printer) const {} void ImmutableMessageFieldGenerator:: GenerateBuilderClearCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { PrintNestedBuilderCondition(printer, - "$name$_ = $type$.getDefaultInstance();\n", + "$name$_ = null;\n", "$name$Builder_.clear();\n"); printer->Print(variables_, "$clear_has_field_bit_builder$\n"); @@ -514,7 +490,7 @@ void ImmutableMessageFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.write$group_or_message$($number$, $name$_);\n" + " output.write$group_or_message$($number$, get$capitalized_name$());\n" "}\n"); } @@ -523,7 +499,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .compute$group_or_message$Size($number$, $name$_);\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc index c4d6995d..45aa8ffe 100644 --- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -35,6 +35,9 @@ // worth. #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_generator.h> #include <google/protobuf/compiler/command_line_interface.h> diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 6713d29a..e331d7a4 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -55,26 +55,6 @@ using internal::WireFormatLite; namespace { -const char* PrimitiveTypeName(JavaType type) { - switch (type) { - case JAVATYPE_INT : return "int"; - case JAVATYPE_LONG : return "long"; - case JAVATYPE_FLOAT : return "float"; - case JAVATYPE_DOUBLE : return "double"; - case JAVATYPE_BOOLEAN: return "boolean"; - case JAVATYPE_STRING : return "java.lang.String"; - case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; - case JAVATYPE_ENUM : return NULL; - case JAVATYPE_MESSAGE: return NULL; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - void SetPrimitiveVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc index ea77f792..f8723f2a 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -33,6 +33,9 @@ #include <google/protobuf/compiler/java/java_shared_code_generator.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_name_resolver.h> @@ -176,7 +179,8 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) { // Invoke internalBuildGeneratedFileFrom() to build the file. printer->Print( "com.google.protobuf.Descriptors.FileDescriptor\n" - " .internalBuildGeneratedFileFrom(descriptorData,\n" + " .internalBuildGeneratedFileFrom(descriptorData,\n"); + printer->Print( " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < dependencies.size(); i++) { diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h index 1bb2f3dc..fdbe2ce8 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.h +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h @@ -36,6 +36,9 @@ #define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__ #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> #include <vector> @@ -68,6 +71,7 @@ class SharedCodeGenerator { void Generate(GeneratorContext* generator_context, vector<string>* file_list); + void GenerateDescriptors(io::Printer* printer); private: diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 8889a744..1c9302af 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -407,6 +407,15 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // 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" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -659,6 +668,15 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n}\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // 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" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -923,6 +941,13 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "String s = input.readStringRequireUtf8();\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // 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"); @@ -932,7 +957,7 @@ GenerateParsingCode(io::Printer* printer) const { " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" "}\n"); - if (CheckUtf8(descriptor_)) { + if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, "$name$_.add(s);\n"); } else { diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc index 916b0ccd..70373c8e 100644 --- a/src/google/protobuf/compiler/mock_code_generator.cc +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -33,6 +33,9 @@ #include <google/protobuf/compiler/mock_code_generator.h> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/testing/file.h> #include <google/protobuf/descriptor.pb.h> diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 474a8f80..0ed80d54 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -84,6 +84,32 @@ TypeNameMap MakeTypeNameTable() { const TypeNameMap kTypeNames = MakeTypeNameTable(); +// Camel-case the field name and append "Entry" for generated map entry name. +// e.g. map<KeyType, ValueType> foo_map => FooMapEntry +string MapEntryName(const string& field_name) { + string result; + static const char kSuffix[] = "Entry"; + result.reserve(field_name.size() + sizeof(kSuffix)); + bool cap_next = true; + for (int i = 0; i < field_name.size(); ++i) { + if (field_name[i] == '_') { + cap_next = true; + } else if (cap_next) { + // Note: Do not use ctype.h due to locales. + if ('a' <= field_name[i] && field_name[i] <= 'z') { + result.push_back(field_name[i] - 'a' + 'A'); + } else { + result.push_back(field_name[i]); + } + cap_next = false; + } else { + result.push_back(field_name[i]); + } + } + result.append(kSuffix); + return result; +} + } // anonymous namespace // Makes code slightly more readable. The meaning of "DO(foo)" is @@ -439,6 +465,8 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { // identifier. return false; } + // Store the syntax into the file. + if (file != NULL) file->set_syntax(syntax_identifier_); } else if (!stop_after_syntax_identifier_) { syntax_identifier_ = "proto2"; } @@ -467,7 +495,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { } bool Parser::ParseSyntaxIdentifier() { - DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'.")); + DO(Consume( + "syntax", + "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'.")); DO(Consume("=")); io::Tokenizer::Token syntax_token = input_->current(); string syntax; @@ -476,10 +506,11 @@ bool Parser::ParseSyntaxIdentifier() { syntax_identifier_ = syntax; - if (syntax != "proto2" && !stop_after_syntax_identifier_) { + if (syntax != "proto2" && syntax != "proto3" && + !stop_after_syntax_identifier_) { AddError(syntax_token.line, syntax_token.column, "Unrecognized syntax identifier \"" + syntax + "\". This parser " - "only recognizes \"proto2\"."); + "only recognizes \"proto2\" and \"proto3\"."); return false; } @@ -673,8 +704,9 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field, LocationRecorder location(field_location, FieldDescriptorProto::kLabelFieldNumber); FieldDescriptorProto::Label label; - DO(ParseLabel(&label, containing_file)); - field->set_label(label); + if (ParseLabel(&label, containing_file)) { + field->set_label(label); + } } return ParseMessageFieldNoLabel(field, messages, parent_location, @@ -690,20 +722,75 @@ bool Parser::ParseMessageFieldNoLabel( int location_field_number_for_nested_type, const LocationRecorder& field_location, const FileDescriptorProto* containing_file) { + MapField map_field; // Parse type. { LocationRecorder location(field_location); // add path later location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE); + bool type_parsed = false; FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32; string type_name; - DO(ParseType(&type, &type_name)); - if (type_name.empty()) { - location.AddPath(FieldDescriptorProto::kTypeFieldNumber); - field->set_type(type); - } else { + + // Special case map field. We only treat the field as a map field if the + // field type name starts with the word "map" with a following "<". + if (TryConsume("map")) { + if (LookingAt("<")) { + map_field.is_map_field = true; + } else { + // False positive + type_parsed = true; + type_name = "map"; + } + } + if (map_field.is_map_field) { + if (field->has_oneof_index()) { + AddError("Map fields are not allowed in oneofs."); + return false; + } + if (field->has_label()) { + AddError( + "Field labels (required/optional/repeated) are not allowed on " + "map fields."); + return false; + } + if (field->has_extendee()) { + AddError("Map fields are not allowed to be extensions."); + return false; + } + field->set_label(FieldDescriptorProto::LABEL_REPEATED); + DO(Consume("<")); + DO(ParseType(&map_field.key_type, &map_field.key_type_name)); + DO(Consume(",")); + DO(ParseType(&map_field.value_type, &map_field.value_type_name)); + DO(Consume(">")); + // Defer setting of the type name of the map field until the + // field name is parsed. Add the source location though. location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); - field->set_type_name(type_name); + } else { + // Handle the case where no explicit label is given for a non-map field. + if (!field->has_label() && DefaultToOptionalFields()) { + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + } + if (!field->has_label()) { + AddError("Expected \"required\", \"optional\", or \"repeated\"."); + // We can actually reasonably recover here by just assuming the user + // forgot the label altogether. + field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + } + + // Handle the case where the actual type is a message or enum named "map", + // which we already consumed in the code above. + if (!type_parsed) { + DO(ParseType(&type, &type_name)); + } + if (type_name.empty()) { + location.AddPath(FieldDescriptorProto::kTypeFieldNumber); + field->set_type(type); + } else { + location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); + field->set_type_name(type_name); + } } } @@ -781,9 +868,42 @@ bool Parser::ParseMessageFieldNoLabel( DO(ConsumeEndOfDeclaration(";", &field_location)); } + // Create a map entry type if this is a map field. + if (map_field.is_map_field) { + GenerateMapEntry(map_field, field, messages); + } + return true; } +void Parser::GenerateMapEntry(const MapField& map_field, + FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages) { + DescriptorProto* entry = messages->Add(); + string entry_name = MapEntryName(field->name()); + field->set_type_name(entry_name); + entry->set_name(entry_name); + entry->mutable_options()->set_map_entry(true); + FieldDescriptorProto* key_field = entry->add_field(); + key_field->set_name("key"); + key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + key_field->set_number(1); + if (map_field.key_type_name.empty()) { + key_field->set_type(map_field.key_type); + } else { + key_field->set_type_name(map_field.key_type_name); + } + FieldDescriptorProto* value_field = entry->add_field(); + value_field->set_name("value"); + value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL); + value_field->set_number(2); + if (map_field.value_type_name.empty()) { + value_field->set_type(map_field.value_type); + } else { + value_field->set_type_name(map_field.value_type_name); + } +} + bool Parser::ParseFieldOptions(FieldDescriptorProto* field, const LocationRecorder& field_location, const FileDescriptorProto* containing_file) { @@ -1588,13 +1708,8 @@ bool Parser::ParseLabel(FieldDescriptorProto::Label* label, } else if (TryConsume("required")) { *label = FieldDescriptorProto::LABEL_REQUIRED; return true; - } else { - AddError("Expected \"required\", \"optional\", or \"repeated\"."); - // We can actually reasonably recover here by just assuming the user - // forgot the label altogether. - *label = FieldDescriptorProto::LABEL_OPTIONAL; - return true; } + return false; } bool Parser::ParseType(FieldDescriptorProto::Type* type, diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index d0a2359b..a15cc705 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -403,7 +403,7 @@ class LIBPROTOBUF_EXPORT Parser { Message* mutable_options); // Parse "required", "optional", or "repeated" and fill in "label" - // with the value. + // with the value. Returns true if shuch a label is consumed. bool ParseLabel(FieldDescriptorProto::Label* label, const FileDescriptorProto* containing_file); @@ -460,6 +460,28 @@ class LIBPROTOBUF_EXPORT Parser { // the ending brace. bool ParseUninterpretedBlock(string* value); + struct MapField { + // Whether the field is a map field. + bool is_map_field; + // The types of the key and value if they are primitive types. + FieldDescriptorProto::Type key_type; + FieldDescriptorProto::Type value_type; + // Or the type names string if the types are customized types. + string key_type_name; + string value_type_name; + + MapField() : is_map_field(false) {} + }; + // Desugar the map syntax to generate a nested map entry message. + void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field, + RepeatedPtrField<DescriptorProto>* messages); + + // Whether fields without label default to optional fields. + bool DefaultToOptionalFields() const { + return syntax_identifier_ == "proto3"; + } + + // ================================================================= io::Tokenizer* input_; diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 9ec29a48..c2206ade 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -33,6 +33,9 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <vector> #include <algorithm> #include <map> @@ -250,6 +253,7 @@ TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) { " required int32 foo = 1;\n" "}\n", + "syntax: 'proto2' " "message_type {" " name: \"TestMessage\"" " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" @@ -265,6 +269,7 @@ TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) { " required int32 foo = 1;\n" "}\n", + "syntax: 'proto2' " "message_type {" " name: \"TestMessage\"" " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" @@ -500,6 +505,54 @@ TEST_F(ParseMessageTest, MultipleOneofs) { "}"); } +TEST_F(ParseMessageTest, Maps) { + ExpectParsesTo( + "message TestMessage {\n" + " map<int32, string> primitive_type_map = 1;\n" + " map<KeyType, ValueType> composite_type_map = 2;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " nested_type {" + " name: \"PrimitiveTypeMapEntry\"" + " field { " + " name: \"key\" number: 1 label:LABEL_OPTIONAL" + " type:TYPE_INT32" + " }" + " field { " + " name: \"value\" number: 2 label:LABEL_OPTIONAL" + " type:TYPE_STRING" + " }" + " options { map_entry: true }" + " }" + " nested_type {" + " name: \"CompositeTypeMapEntry\"" + " field { " + " name: \"key\" number: 1 label:LABEL_OPTIONAL" + " type_name: \"KeyType\"" + " }" + " field { " + " name: \"value\" number: 2 label:LABEL_OPTIONAL" + " type_name: \"ValueType\"" + " }" + " options { map_entry: true }" + " }" + " field {" + " name: \"primitive_type_map\"" + " label: LABEL_REPEATED" + " type_name: \"PrimitiveTypeMapEntry\"" + " number: 1" + " }" + " field {" + " name: \"composite_type_map\"" + " label: LABEL_REPEATED" + " type_name: \"CompositeTypeMapEntry\"" + " number: 2" + " }" + "}"); +} + TEST_F(ParseMessageTest, Group) { ExpectParsesTo( "message TestMessage {\n" @@ -639,6 +692,20 @@ TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) { " type_name:\"TestMessage\" extendee: \"Extendee1\" }"); } +TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) { + ExpectParsesTo( + "syntax = \"proto3\";\n" + "message TestMessage {\n" + " int32 foo = 1;\n" + " optional int32 bar = 2;\n" + "}\n", + + "syntax: \"proto3\" " + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }" + " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }"); +} // =================================================================== @@ -828,9 +895,9 @@ typedef ParserTest ParseErrorTest; TEST_F(ParseErrorTest, MissingSyntaxIdentifier) { require_syntax_identifier_ = true; - ExpectHasEarlyExitErrors( - "message TestMessage {}", - "0:0: File must begin with 'syntax = \"proto2\";'.\n"); + ExpectHasEarlyExitErrors("message TestMessage {}", + "0:0: File must begin with a syntax statement, e.g. " + "'syntax = \"proto2\";'.\n"); EXPECT_EQ("", parser_->GetSyntaxIdentifier()); } @@ -838,7 +905,7 @@ TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) { ExpectHasEarlyExitErrors( "syntax = \"no_such_syntax\";", "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser " - "only recognizes \"proto2\".\n"); + "only recognizes \"proto2\" and \"proto3\".\n"); EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier()); } @@ -1041,6 +1108,55 @@ TEST_F(ParseErrorTest, LabelInOneof) { "/ repeated).\n"); } +TEST_F(ParseErrorTest, MapInOneof) { + ExpectHasErrors( + "message TestMessage {\n" + " oneof foo {\n" + " map<int32, int32> foo_map = 1;\n" + " map message_field = 2;\n" // a normal message field is OK + " }\n" + "}\n", + "2:7: Map fields are not allowed in oneofs.\n"); +} + +TEST_F(ParseErrorTest, LabelForMap) { + ExpectHasErrors( + "message TestMessage {\n" + " optional map<int32, int32> int_map = 1;\n" + " required map<int32, int32> int_map2 = 2;\n" + " repeated map<int32, int32> int_map3 = 3;\n" + " optional map map_message = 4;\n" // a normal message field is OK + "}\n", + "1:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n" + "2:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n" + "3:14: Field labels (required/optional/repeated) are not allowed on map " + "fields.\n"); +} + +TEST_F(ParseErrorTest, MalformedMaps) { + ExpectHasErrors( + "message TestMessage {\n" + " map map_message = 1;\n" // a normal message field lacking label + " map<string> str_map = 2;\n" + " map<string,> str_map2 = 3;\n" + " map<,string> str_map3 = 4;\n" + " map<> empty_map = 5;\n" + " map<string,string str_map6 = 6;\n" + "}" + "extend SomeMessage {\n" + " map<int32, int32> int_map = 1;\n" + "}", + "1:6: Expected \"required\", \"optional\", or \"repeated\".\n" + "2:12: Expected \",\".\n" + "3:13: Expected type name.\n" + "4:6: Expected type name.\n" + "5:6: Expected type name.\n" + "6:20: Expected \">\".\n" + "8:5: Map fields are not allowed to be extensions.\n"); +} + TEST_F(ParseErrorTest, GroupNotCapitalized) { ExpectHasErrors( "message TestMessage {\n" @@ -1413,7 +1529,7 @@ TEST_F(ParserValidationErrorTest, ResovledUndefinedOptionError) { // definitions again afoter parsing (note, however, that the order of messages // cannot be guaranteed to be the same) -typedef ParserTest ParseDecriptorDebugTest; +typedef ParserTest ParseDescriptorDebugTest; class CompareDescriptorNames { public: @@ -1447,7 +1563,28 @@ void SortMessages(FileDescriptorProto *file_descriptor_proto) { sort(data, data + size, CompareDescriptorNames()); } -TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) { +// Strips the message and enum field type names for comparison purpose only. +void StripFieldTypeName(DescriptorProto* proto) { + for (int i = 0; i < proto->field_size(); ++i) { + string type_name = proto->field(i).type_name(); + string::size_type pos = type_name.find_last_of("."); + if (pos != string::npos) { + proto->mutable_field(i)->mutable_type_name()->assign( + type_name.begin() + pos + 1, type_name.end()); + } + } + for (int i = 0; i < proto->nested_type_size(); ++i) { + StripFieldTypeName(proto->mutable_nested_type(i)); + } +} + +void StripFieldTypeName(FileDescriptorProto* file_proto) { + for (int i = 0; i < file_proto->message_type_size(); ++i) { + StripFieldTypeName(file_proto->mutable_message_type(i)); + } +} + +TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) { const FileDescriptor* original_file = protobuf_unittest::TestAllTypes::descriptor()->file(); FileDescriptorProto expected; @@ -1499,7 +1636,7 @@ TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) { EXPECT_EQ(expected.DebugString(), parsed.DebugString()); } -TEST_F(ParseDecriptorDebugTest, TestCustomOptions) { +TEST_F(ParseDescriptorDebugTest, TestCustomOptions) { const FileDescriptor* original_file = protobuf_unittest::AggregateMessage::descriptor()->file(); FileDescriptorProto expected; @@ -1538,6 +1675,106 @@ TEST_F(ParseDecriptorDebugTest, TestCustomOptions) { EXPECT_EQ(expected.DebugString(), parsed.DebugString()); } +// Ensure that DebugStringWithOptions(), with |include_comments| set to true, +// includes comments from the original parser input in all of the appropriate +// places. +TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) { + SetupParser( + "// Message comment.\n" + "message TestMessage1 {\n" + " // Field comment.\n" + " optional int32 foo = 1;\n" + "\n" + " // Nested-message comment.\n" + " message NestedMessage {\n" + " optional int32 bar = 1;\n" + " }\n" + "}\n" + "\n" + "// Enum comment.\n" + "enum MyEnumType {\n" + " // Enum-value comment.\n" + " ASDF = 1;\n" + "}\n" + "\n" + "// Service comment.\n" + "service MyService {\n" + " // RPC comment.\n" + " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n" + "}\n"); + + FileDescriptorProto parsed_desc; + parsed_desc.set_name("foo.proto"); + SourceLocationTable source_locations; + parser_->RecordSourceLocationsTo(&source_locations); + parser_->Parse(input_.get(), &parsed_desc); + EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type); + ASSERT_EQ("", error_collector_.text_); + + // We need to import the FileDescriptorProto to get a FileDescriptor. + MockValidationErrorCollector collector(source_locations, &error_collector_); + const FileDescriptor* descriptor = + pool_.BuildFileCollectingErrors(parsed_desc, &collector); + ASSERT_TRUE(descriptor != NULL); + + DebugStringOptions debug_string_options; + debug_string_options.include_comments = true; + const string debug_string = + descriptor->DebugStringWithOptions(debug_string_options); + + // Ensure that each of the comments appears somewhere in the DebugString(), + // and that these comments appear in order. We don't test the exact comment + // placement or formatting, because we do not want to be too fragile here. + const char* expected_comments[] = { + "Message comment.", + "Field comment", + "Nested-message comment", + "Enum comment", + "Enum-value comment", + "Service comment", + "RPC comment", + }; + + for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) { + string::size_type found_pos = debug_string.find(expected_comments[i]); + ASSERT_TRUE(found_pos != string::npos); + } +} + +TEST_F(ParseDescriptorDebugTest, TestMaps) { + SetupParser( + "syntax = \"proto3\"; " + "message Foo { " + " message Bar { } " + " map<int32, Bar> enum_message_map = 1; " + " map<string, float> primitive_map = 2; " + "} "); + FileDescriptorProto original; + EXPECT_TRUE(parser_->Parse(input_.get(), &original)); + original.set_name("foo.proto"); + const FileDescriptor* file = pool_.BuildFile(original); + ASSERT_TRUE(file != NULL); + + // Make sure the debug string uses map syntax and does not have the auto + // generated entry. + string debug_string = file->DebugString(); + EXPECT_TRUE(debug_string.find("map<") != string::npos); + EXPECT_TRUE(debug_string.find("option map_entry") == string::npos); + EXPECT_TRUE(debug_string.find("MapEntry") == string::npos); + + // Make sure the descriptor debug string is parsable. + FileDescriptorProto parsed; + SetupParser(debug_string.c_str()); + parsed.set_name("foo.proto"); + ASSERT_TRUE(parser_->Parse(input_.get(), &parsed)); + + original.clear_source_code_info(); + parsed.clear_source_code_info(); + StripFieldTypeName(&original); + StripFieldTypeName(&parsed); + EXPECT_EQ(original.DebugString(), parsed.DebugString()); +} + // =================================================================== // SourceCodeInfo tests. diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index b5cd01b5..efa64f3d 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -53,11 +53,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorRequest::default_instance_, CodeGeneratorRequest_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(CodeGeneratorRequest)); + sizeof(CodeGeneratorRequest), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_)); CodeGeneratorResponse_descriptor_ = file->message_type(1); static const int CodeGeneratorResponse_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), @@ -69,11 +70,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorResponse::default_instance_, CodeGeneratorResponse_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(CodeGeneratorResponse)); + sizeof(CodeGeneratorResponse), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_)); CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); static const int CodeGeneratorResponse_File_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), @@ -86,11 +88,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { CodeGeneratorResponse_File::default_instance_, CodeGeneratorResponse_File_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(CodeGeneratorResponse_File)); + sizeof(CodeGeneratorResponse_File), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_)); } namespace { @@ -169,16 +172,27 @@ const int CodeGeneratorRequest::kProtoFileFieldNumber; #endif // !_MSC_VER CodeGeneratorRequest::CodeGeneratorRequest() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest) } +CodeGeneratorRequest::CodeGeneratorRequest(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + file_to_generate_(arena), + proto_file_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorRequest) +} + void CodeGeneratorRequest::InitAsDefaultInstance() { } CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorRequest) @@ -187,7 +201,7 @@ CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) void CodeGeneratorRequest::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + parameter_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -197,13 +211,21 @@ CodeGeneratorRequest::~CodeGeneratorRequest() { } void CodeGeneratorRequest::SharedDtor() { - if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete parameter_; + if (GetArenaNoVirtual() != NULL) { + return; } + + parameter_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void CodeGeneratorRequest::ArenaDtor(void* object) { + CodeGeneratorRequest* _this = reinterpret_cast< CodeGeneratorRequest* >(object); + (void)_this; +} +void CodeGeneratorRequest::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void CodeGeneratorRequest::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -221,20 +243,20 @@ const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() { CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL; -CodeGeneratorRequest* CodeGeneratorRequest::New() const { - return new CodeGeneratorRequest; +CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage<CodeGeneratorRequest>(arena); } void CodeGeneratorRequest::Clear() { if (has_parameter()) { - if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_->clear(); - } + parameter_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } file_to_generate_.Clear(); proto_file_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool CodeGeneratorRequest::MergePartialFromCodedStream( @@ -257,7 +279,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream( this->file_to_generate(this->file_to_generate_size() - 1).data(), this->file_to_generate(this->file_to_generate_size() - 1).length(), ::google::protobuf::internal::WireFormat::PARSE, - "file_to_generate"); + "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); } else { goto handle_unusual; } @@ -275,7 +297,7 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->parameter().data(), this->parameter().length(), ::google::protobuf::internal::WireFormat::PARSE, - "parameter"); + "google.protobuf.compiler.CodeGeneratorRequest.parameter"); } else { goto handle_unusual; } @@ -327,7 +349,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->file_to_generate(i).data(), this->file_to_generate(i).length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "file_to_generate"); + "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); ::google::protobuf::internal::WireFormatLite::WriteString( 1, this->file_to_generate(i), output); } @@ -337,7 +359,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->parameter().data(), this->parameter().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "parameter"); + "google.protobuf.compiler.CodeGeneratorRequest.parameter"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->parameter(), output); } @@ -348,7 +370,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( 15, this->proto_file(i), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -363,7 +385,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->file_to_generate(i).data(), this->file_to_generate(i).length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "file_to_generate"); + "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); target = ::google::protobuf::internal::WireFormatLite:: WriteStringToArray(1, this->file_to_generate(i), target); } @@ -373,7 +395,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->parameter().data(), this->parameter().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "parameter"); + "google.protobuf.compiler.CodeGeneratorRequest.parameter"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 2, this->parameter(), target); @@ -386,7 +408,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( 15, this->proto_file(i), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -397,15 +419,13 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( int CodeGeneratorRequest::ByteSize() const { int total_size = 0; - if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { - // optional string parameter = 2; - if (has_parameter()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->parameter()); - } - + // optional string parameter = 2; + if (has_parameter()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->parameter()); } + // repeated string file_to_generate = 1; total_size += 1 * this->file_to_generate_size(); for (int i = 0; i < this->file_to_generate_size(); i++) { @@ -421,7 +441,7 @@ int CodeGeneratorRequest::ByteSize() const { this->proto_file(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -453,7 +473,9 @@ void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { set_parameter(from.parameter()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) { @@ -475,15 +497,29 @@ bool CodeGeneratorRequest::IsInitialized() const { } void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) { - if (other != this) { - file_to_generate_.Swap(&other->file_to_generate_); - std::swap(parameter_, other->parameter_); - proto_file_.Swap(&other->proto_file_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + CodeGeneratorRequest temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void CodeGeneratorRequest::UnsafeArenaSwap(CodeGeneratorRequest* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) { + file_to_generate_.UnsafeArenaSwap(&other->file_to_generate_); + parameter_.Swap(&other->parameter_); + proto_file_.UnsafeArenaSwap(&other->proto_file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} ::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -503,16 +539,25 @@ const int CodeGeneratorResponse_File::kContentFieldNumber; #endif // !_MSC_VER CodeGeneratorResponse_File::CodeGeneratorResponse_File() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File) } +CodeGeneratorResponse_File::CodeGeneratorResponse_File(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse.File) +} + void CodeGeneratorResponse_File::InitAsDefaultInstance() { } CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File) @@ -521,9 +566,9 @@ CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorRespon void CodeGeneratorResponse_File::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + insertion_point_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + content_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -533,19 +578,23 @@ CodeGeneratorResponse_File::~CodeGeneratorResponse_File() { } void CodeGeneratorResponse_File::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; - } - if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete insertion_point_; - } - if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete content_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + insertion_point_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + content_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void CodeGeneratorResponse_File::ArenaDtor(void* object) { + CodeGeneratorResponse_File* _this = reinterpret_cast< CodeGeneratorResponse_File* >(object); + (void)_this; +} +void CodeGeneratorResponse_File::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void CodeGeneratorResponse_File::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -563,30 +612,26 @@ const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL; -CodeGeneratorResponse_File* CodeGeneratorResponse_File::New() const { - return new CodeGeneratorResponse_File; +CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage<CodeGeneratorResponse_File>(arena); } void CodeGeneratorResponse_File::Clear() { if (_has_bits_[0 / 32] & 7) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_insertion_point()) { - if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_->clear(); - } + insertion_point_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_content()) { - if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_->clear(); - } + content_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } } ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool CodeGeneratorResponse_File::MergePartialFromCodedStream( @@ -607,7 +652,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.compiler.CodeGeneratorResponse.File.name"); } else { goto handle_unusual; } @@ -624,7 +669,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->insertion_point().data(), this->insertion_point().length(), ::google::protobuf::internal::WireFormat::PARSE, - "insertion_point"); + "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point"); } else { goto handle_unusual; } @@ -641,7 +686,7 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->content().data(), this->content().length(), ::google::protobuf::internal::WireFormat::PARSE, - "content"); + "google.protobuf.compiler.CodeGeneratorResponse.File.content"); } else { goto handle_unusual; } @@ -679,7 +724,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.compiler.CodeGeneratorResponse.File.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -689,7 +734,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->insertion_point().data(), this->insertion_point().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "insertion_point"); + "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->insertion_point(), output); } @@ -699,12 +744,12 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->content().data(), this->content().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "content"); + "google.protobuf.compiler.CodeGeneratorResponse.File.content"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 15, this->content(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -719,7 +764,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.compiler.CodeGeneratorResponse.File.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -730,7 +775,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->insertion_point().data(), this->insertion_point().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "insertion_point"); + "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 2, this->insertion_point(), target); @@ -741,13 +786,13 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->content().data(), this->content().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "content"); + "google.protobuf.compiler.CodeGeneratorResponse.File.content"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 15, this->content(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -758,7 +803,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( int CodeGeneratorResponse_File::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 7) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -781,7 +826,7 @@ int CodeGeneratorResponse_File::ByteSize() const { } } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -817,7 +862,9 @@ void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& fro set_content(from.content()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) { @@ -838,15 +885,29 @@ bool CodeGeneratorResponse_File::IsInitialized() const { } void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(insertion_point_, other->insertion_point_); - std::swap(content_, other->content_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + CodeGeneratorResponse_File temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void CodeGeneratorResponse_File::UnsafeArenaSwap(CodeGeneratorResponse_File* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) { + name_.Swap(&other->name_); + insertion_point_.Swap(&other->insertion_point_); + content_.Swap(&other->content_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} ::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -865,16 +926,26 @@ const int CodeGeneratorResponse::kFileFieldNumber; #endif // !_MSC_VER CodeGeneratorResponse::CodeGeneratorResponse() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse) } +CodeGeneratorResponse::CodeGeneratorResponse(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + file_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse) +} + void CodeGeneratorResponse::InitAsDefaultInstance() { } CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse) @@ -883,7 +954,7 @@ CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) void CodeGeneratorResponse::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + error_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -893,13 +964,21 @@ CodeGeneratorResponse::~CodeGeneratorResponse() { } void CodeGeneratorResponse::SharedDtor() { - if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete error_; + if (GetArenaNoVirtual() != NULL) { + return; } + + error_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void CodeGeneratorResponse::ArenaDtor(void* object) { + CodeGeneratorResponse* _this = reinterpret_cast< CodeGeneratorResponse* >(object); + (void)_this; +} +void CodeGeneratorResponse::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void CodeGeneratorResponse::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -917,19 +996,19 @@ const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() { CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL; -CodeGeneratorResponse* CodeGeneratorResponse::New() const { - return new CodeGeneratorResponse; +CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage<CodeGeneratorResponse>(arena); } void CodeGeneratorResponse::Clear() { if (has_error()) { - if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_->clear(); - } + error_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } file_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool CodeGeneratorResponse::MergePartialFromCodedStream( @@ -950,7 +1029,7 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->error().data(), this->error().length(), ::google::protobuf::internal::WireFormat::PARSE, - "error"); + "google.protobuf.compiler.CodeGeneratorResponse.error"); } else { goto handle_unusual; } @@ -1002,7 +1081,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->error().data(), this->error().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "error"); + "google.protobuf.compiler.CodeGeneratorResponse.error"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->error(), output); } @@ -1013,7 +1092,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( 15, this->file(i), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -1028,7 +1107,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->error().data(), this->error().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "error"); + "google.protobuf.compiler.CodeGeneratorResponse.error"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->error(), target); @@ -1041,7 +1120,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( 15, this->file(i), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -1052,15 +1131,13 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( int CodeGeneratorResponse::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional string error = 1; - if (has_error()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->error()); - } - + // optional string error = 1; + if (has_error()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->error()); } + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; total_size += 1 * this->file_size(); for (int i = 0; i < this->file_size(); i++) { @@ -1069,7 +1146,7 @@ int CodeGeneratorResponse::ByteSize() const { this->file(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -1100,7 +1177,9 @@ void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { set_error(from.error()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) { @@ -1121,14 +1200,28 @@ bool CodeGeneratorResponse::IsInitialized() const { } void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) { - if (other != this) { - std::swap(error_, other->error_); - file_.Swap(&other->file_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + CodeGeneratorResponse temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void CodeGeneratorResponse::UnsafeArenaSwap(CodeGeneratorResponse* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { + error_.Swap(&other->error_); + file_.UnsafeArenaSwap(&other->file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} ::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const { protobuf_AssignDescriptorsOnce(); diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 567b30ef..636992a6 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -5,6 +5,7 @@ #define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED #include <string> +#include <stdint.h> #include <google/protobuf/stubs/common.h> @@ -19,7 +20,10 @@ #error regenerate this file with a newer version of protoc. #endif +#include <google/protobuf/arena.h> +#include <google/protobuf/arenastring.h> #include <google/protobuf/generated_message_util.h> +#include <google/protobuf/metadata.h> #include <google/protobuf/message.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> @@ -55,21 +59,28 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message } inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; + return _internal_metadata_.unknown_fields(); } inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; + return _internal_metadata_.mutable_unknown_fields(); } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorRequest& default_instance(); + void UnsafeArenaSwap(CodeGeneratorRequest* other); void Swap(CodeGeneratorRequest* other); // implements Message ---------------------------------------------- - CodeGeneratorRequest* New() const; + inline CodeGeneratorRequest* New() const { return New(NULL); } + + CodeGeneratorRequest* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const CodeGeneratorRequest& from); @@ -88,7 +99,21 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(CodeGeneratorRequest* other); + protected: + explicit CodeGeneratorRequest(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } public: + ::google::protobuf::Metadata GetMetadata() const; // nested types ---------------------------------------------------- @@ -122,6 +147,9 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message inline ::std::string* mutable_parameter(); inline ::std::string* release_parameter(); inline void set_allocated_parameter(::std::string* parameter); + inline ::std::string* unsafe_arena_release_parameter(); + inline void unsafe_arena_set_allocated_parameter( + ::std::string* parameter); // repeated .google.protobuf.FileDescriptorProto proto_file = 15; inline int proto_file_size() const; @@ -140,12 +168,14 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message inline void set_has_parameter(); inline void clear_has_parameter(); - ::google::protobuf::UnknownFieldSet _unknown_fields_; - + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; - ::std::string* parameter_; + ::google::protobuf::internal::ArenaStringPtr parameter_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); @@ -169,21 +199,28 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M } inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; + return _internal_metadata_.unknown_fields(); } inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; + return _internal_metadata_.mutable_unknown_fields(); } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse_File& default_instance(); + void UnsafeArenaSwap(CodeGeneratorResponse_File* other); void Swap(CodeGeneratorResponse_File* other); // implements Message ---------------------------------------------- - CodeGeneratorResponse_File* New() const; + inline CodeGeneratorResponse_File* New() const { return New(NULL); } + + CodeGeneratorResponse_File* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const CodeGeneratorResponse_File& from); @@ -202,7 +239,21 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(CodeGeneratorResponse_File* other); + protected: + explicit CodeGeneratorResponse_File(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } public: + ::google::protobuf::Metadata GetMetadata() const; // nested types ---------------------------------------------------- @@ -220,6 +271,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M inline ::std::string* mutable_name(); inline ::std::string* release_name(); inline void set_allocated_name(::std::string* name); + inline ::std::string* unsafe_arena_release_name(); + inline void unsafe_arena_set_allocated_name( + ::std::string* name); // optional string insertion_point = 2; inline bool has_insertion_point() const; @@ -232,6 +286,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M inline ::std::string* mutable_insertion_point(); inline ::std::string* release_insertion_point(); inline void set_allocated_insertion_point(::std::string* insertion_point); + inline ::std::string* unsafe_arena_release_insertion_point(); + inline void unsafe_arena_set_allocated_insertion_point( + ::std::string* insertion_point); // optional string content = 15; inline bool has_content() const; @@ -244,6 +301,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M inline ::std::string* mutable_content(); inline ::std::string* release_content(); inline void set_allocated_content(::std::string* content); + inline ::std::string* unsafe_arena_release_content(); + inline void unsafe_arena_set_allocated_content( + ::std::string* content); // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) private: @@ -254,13 +314,15 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M inline void set_has_content(); inline void clear_has_content(); - ::google::protobuf::UnknownFieldSet _unknown_fields_; - + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; - ::std::string* name_; - ::std::string* insertion_point_; - ::std::string* content_; + ::google::protobuf::internal::ArenaStringPtr name_; + ::google::protobuf::internal::ArenaStringPtr insertion_point_; + ::google::protobuf::internal::ArenaStringPtr content_; friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); @@ -283,21 +345,28 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag } inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { - return _unknown_fields_; + return _internal_metadata_.unknown_fields(); } inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { - return &_unknown_fields_; + return _internal_metadata_.mutable_unknown_fields(); } + inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); } + inline void* GetMaybeArenaPointer() const { + return MaybeArenaPtr(); + } static const ::google::protobuf::Descriptor* descriptor(); static const CodeGeneratorResponse& default_instance(); + void UnsafeArenaSwap(CodeGeneratorResponse* other); void Swap(CodeGeneratorResponse* other); // implements Message ---------------------------------------------- - CodeGeneratorResponse* New() const; + inline CodeGeneratorResponse* New() const { return New(NULL); } + + CodeGeneratorResponse* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const CodeGeneratorResponse& from); @@ -316,7 +385,21 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(CodeGeneratorResponse* other); + protected: + explicit CodeGeneratorResponse(::google::protobuf::Arena* arena); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::google::protobuf::Arena* arena); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } public: + ::google::protobuf::Metadata GetMetadata() const; // nested types ---------------------------------------------------- @@ -336,6 +419,9 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag inline ::std::string* mutable_error(); inline ::std::string* release_error(); inline void set_allocated_error(::std::string* error); + inline ::std::string* unsafe_arena_release_error(); + inline void unsafe_arena_set_allocated_error( + ::std::string* error); // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; inline int file_size() const; @@ -354,11 +440,13 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag inline void set_has_error(); inline void clear_has_error(); - ::google::protobuf::UnknownFieldSet _unknown_fields_; - + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; - ::std::string* error_; + ::google::protobuf::internal::ArenaStringPtr error_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); @@ -439,68 +527,67 @@ inline void CodeGeneratorRequest::clear_has_parameter() { _has_bits_[0] &= ~0x00000002u; } inline void CodeGeneratorRequest::clear_parameter() { - if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_->clear(); - } + parameter_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_parameter(); } inline const ::std::string& CodeGeneratorRequest::parameter() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter) - return *parameter_; + return parameter_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) { set_has_parameter(); - if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_ = new ::std::string; - } - parameter_->assign(value); + parameter_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter) } inline void CodeGeneratorRequest::set_parameter(const char* value) { set_has_parameter(); - if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_ = new ::std::string; - } - parameter_->assign(value); + parameter_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter) } -inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { +inline void CodeGeneratorRequest::set_parameter(const char* value, + size_t size) { set_has_parameter(); - if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_ = new ::std::string; - } - parameter_->assign(reinterpret_cast<const char*>(value), size); + parameter_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter) } inline ::std::string* CodeGeneratorRequest::mutable_parameter() { set_has_parameter(); - if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - parameter_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter) - return parameter_; + return parameter_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* CodeGeneratorRequest::release_parameter() { clear_has_parameter(); - if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = parameter_; - parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return parameter_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* CodeGeneratorRequest::unsafe_arena_release_parameter() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_parameter(); + return parameter_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { - if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete parameter_; + if (parameter != NULL) { + set_has_parameter(); + } else { + clear_has_parameter(); } - if (parameter) { + parameter_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter) +} +inline void CodeGeneratorRequest::unsafe_arena_set_allocated_parameter( + ::std::string* parameter) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (parameter != NULL) { set_has_parameter(); - parameter_ = parameter; } else { clear_has_parameter(); - parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_parameter(); + parameter_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + parameter, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter) } @@ -549,68 +636,67 @@ inline void CodeGeneratorResponse_File::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void CodeGeneratorResponse_File::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& CodeGeneratorResponse_File::name() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } - name_->assign(value); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name) } inline void CodeGeneratorResponse_File::set_name(const char* value) { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } - name_->assign(value); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name) } -inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { +inline void CodeGeneratorResponse_File::set_name(const char* value, + size_t size) { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } - name_->assign(reinterpret_cast<const char*>(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name) } inline ::std::string* CodeGeneratorResponse_File::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* CodeGeneratorResponse_File::release_name() { clear_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = name_; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* CodeGeneratorResponse_File::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (name != NULL) { + set_has_name(); + } else { + clear_has_name(); } - if (name) { + name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name) +} +inline void CodeGeneratorResponse_File::unsafe_arena_set_allocated_name( + ::std::string* name) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (name != NULL) { set_has_name(); - name_ = name; } else { clear_has_name(); - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_name(); + name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + name, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name) } @@ -625,68 +711,67 @@ inline void CodeGeneratorResponse_File::clear_has_insertion_point() { _has_bits_[0] &= ~0x00000002u; } inline void CodeGeneratorResponse_File::clear_insertion_point() { - if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_->clear(); - } + insertion_point_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_insertion_point(); } inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) - return *insertion_point_; + return insertion_point_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { set_has_insertion_point(); - if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_ = new ::std::string; - } - insertion_point_->assign(value); + insertion_point_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) { set_has_insertion_point(); - if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_ = new ::std::string; - } - insertion_point_->assign(value); + insertion_point_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } -inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, + size_t size) { set_has_insertion_point(); - if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_ = new ::std::string; - } - insertion_point_->assign(reinterpret_cast<const char*>(value), size); + insertion_point_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { set_has_insertion_point(); - if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - insertion_point_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) - return insertion_point_; + return insertion_point_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() { clear_has_insertion_point(); - if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = insertion_point_; - insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return insertion_point_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* CodeGeneratorResponse_File::unsafe_arena_release_insertion_point() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_insertion_point(); + return insertion_point_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { - if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete insertion_point_; + if (insertion_point != NULL) { + set_has_insertion_point(); + } else { + clear_has_insertion_point(); } - if (insertion_point) { + insertion_point_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) +} +inline void CodeGeneratorResponse_File::unsafe_arena_set_allocated_insertion_point( + ::std::string* insertion_point) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (insertion_point != NULL) { set_has_insertion_point(); - insertion_point_ = insertion_point; } else { clear_has_insertion_point(); - insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_insertion_point(); + insertion_point_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + insertion_point, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) } @@ -701,68 +786,67 @@ inline void CodeGeneratorResponse_File::clear_has_content() { _has_bits_[0] &= ~0x00000004u; } inline void CodeGeneratorResponse_File::clear_content() { - if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_->clear(); - } + content_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_content(); } inline const ::std::string& CodeGeneratorResponse_File::content() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content) - return *content_; + return content_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) { set_has_content(); - if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_ = new ::std::string; - } - content_->assign(value); + content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content) } inline void CodeGeneratorResponse_File::set_content(const char* value) { set_has_content(); - if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_ = new ::std::string; - } - content_->assign(value); + content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content) } -inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { +inline void CodeGeneratorResponse_File::set_content(const char* value, + size_t size) { set_has_content(); - if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_ = new ::std::string; - } - content_->assign(reinterpret_cast<const char*>(value), size); + content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content) } inline ::std::string* CodeGeneratorResponse_File::mutable_content() { set_has_content(); - if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - content_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content) - return content_; + return content_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* CodeGeneratorResponse_File::release_content() { clear_has_content(); - if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = content_; - content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return content_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* CodeGeneratorResponse_File::unsafe_arena_release_content() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_content(); + return content_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { - if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete content_; + if (content != NULL) { + set_has_content(); + } else { + clear_has_content(); } - if (content) { + content_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) +} +inline void CodeGeneratorResponse_File::unsafe_arena_set_allocated_content( + ::std::string* content) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (content != NULL) { set_has_content(); - content_ = content; } else { clear_has_content(); - content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_content(); + content_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + content, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content) } @@ -781,68 +865,67 @@ inline void CodeGeneratorResponse::clear_has_error() { _has_bits_[0] &= ~0x00000001u; } inline void CodeGeneratorResponse::clear_error() { - if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_->clear(); - } + error_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_error(); } inline const ::std::string& CodeGeneratorResponse::error() const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error) - return *error_; + return error_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void CodeGeneratorResponse::set_error(const ::std::string& value) { set_has_error(); - if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_ = new ::std::string; - } - error_->assign(value); + error_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error) } inline void CodeGeneratorResponse::set_error(const char* value) { set_has_error(); - if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_ = new ::std::string; - } - error_->assign(value); + error_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error) } -inline void CodeGeneratorResponse::set_error(const char* value, size_t size) { +inline void CodeGeneratorResponse::set_error(const char* value, + size_t size) { set_has_error(); - if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_ = new ::std::string; - } - error_->assign(reinterpret_cast<const char*>(value), size); + error_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast<const char*>(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error) } inline ::std::string* CodeGeneratorResponse::mutable_error() { set_has_error(); - if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - error_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error) - return error_; + return error_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* CodeGeneratorResponse::release_error() { clear_has_error(); - if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = error_; - error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return error_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* CodeGeneratorResponse::unsafe_arena_release_error() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_error(); + return error_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) { - if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete error_; + if (error != NULL) { + set_has_error(); + } else { + clear_has_error(); } - if (error) { + error_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error) +} +inline void CodeGeneratorResponse::unsafe_arena_set_allocated_error( + ::std::string* error) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (error != NULL) { set_has_error(); - error_ = error; } else { clear_has_error(); - error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_error(); + error_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + error, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error) } @@ -888,8 +971,8 @@ namespace google { namespace protobuf { -} // namespace google } // namespace protobuf +} // namespace google #endif // SWIG // @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto index b65379d7..e627289b 100644 --- a/src/google/protobuf/compiler/plugin.proto +++ b/src/google/protobuf/compiler/plugin.proto @@ -44,6 +44,7 @@ // plugin should be named "protoc-gen-$NAME", and will then be used when the // flag "--${NAME}_out" is passed to protoc. +syntax = "proto2"; package google.protobuf.compiler; option java_package = "com.google.protobuf.compiler"; option java_outer_classname = "PluginProtos"; diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 15e05da9..d72ca207 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -44,11 +44,15 @@ // performance-minded Python code leverage the fast C++ implementation // directly. +#include <google/protobuf/stubs/hash.h> #include <limits> #include <map> -#include <utility> #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <string> +#include <utility> #include <vector> #include <google/protobuf/compiler/python/python_generator.h> @@ -69,6 +73,41 @@ namespace python { namespace { +const char* const kKeywordList[] = { + "and", "as", "break", "class", "continue", "def", "elif", "else", "except", + "False", "for", "from", "if", "import", "not", "or", "raise", "return", + "True", "try", "with", "while", "yield" +}; + +hash_set<string> MakeKeywordsMap() { + hash_set<string> result; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); ++i) { + result.insert(kKeywordList[i]); + } + return result; +} + +hash_set<string>* keywords_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(keywords_once_); + +void InitKeywords() { + keywords_ = new hash_set<string>(); + *keywords_ = MakeKeywordsMap(); +} + +hash_set<string>& GetKeywords() { + ::google::protobuf::GoogleOnceInit(&keywords_once_, &InitKeywords); + return *keywords_; +} + +string FieldName(const FieldDescriptor& field) { + string result = field.name(); + if (GetKeywords().count(result) > 0) { + result.append("_"); + } + return result; +} + // Returns a copy of |filename| with any trailing ".protodevel" or ".proto // suffix stripped. // TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc. @@ -88,6 +127,37 @@ string ModuleName(const string& filename) { } +// Returns the alias we assign to the module of the given .proto filename +// when importing. See testPackageInitializationImport in +// google/protobuf/python/reflection_test.py +// to see why we need the alias. +string ModuleAlias(const string& filename) { + string module_name = ModuleName(filename); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + GlobalReplaceSubstring("_", "__", &module_name); + GlobalReplaceSubstring(".", "_dot_", &module_name); + return module_name; +} + + +// Returns an import statement of form "from X.Y.Z import T" for the given +// .proto filename. +string ModuleImportStatement(const string& filename) { + string module_name = ModuleName(filename); + int last_dot_pos = module_name.rfind('.'); + if (last_dot_pos == string::npos) { + // NOTE(petya): this is not tested as it would require a protocol buffer + // outside of any package, and I don't think that is easily achievable. + return "import " + module_name; + } else { + return "from " + module_name.substr(0, last_dot_pos) + " import " + + module_name.substr(last_dot_pos + 1); + } +} + + // Returns the name of all containing types for descriptor, // in order from outermost to innermost, followed by descriptor's // own name. Each name is separated by |separator|. @@ -309,9 +379,12 @@ bool Generator::Generate(const FileDescriptor* file, // Prints Python imports for all modules imported by |file|. void Generator::PrintImports() const { for (int i = 0; i < file_->dependency_count(); ++i) { - string module_name = ModuleName(file_->dependency(i)->name()); - printer_->Print("import $module$\n", "module", - module_name); + const string& filename = file_->dependency(i)->name(); + string import_statement = ModuleImportStatement(filename); + string module_alias = ModuleAlias(filename); + printer_->Print("$statement$ as $alias$\n", "statement", + import_statement, "alias", module_alias); + CopyPublicDependenciesAliases(module_alias, file_->dependency(i)); } printer_->Print("\n"); @@ -342,8 +415,9 @@ void Generator::PrintFileDescriptor() const { if (file_->dependency_count() != 0) { printer_->Print(",\ndependencies=["); for (int i = 0; i < file_->dependency_count(); ++i) { - string module_name = ModuleName(file_->dependency(i)->name()); - printer_->Print("$module_name$.DESCRIPTOR,", "module_name", module_name); + string module_alias = ModuleAlias(file_->dependency(i)->name()); + printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", + module_alias); } printer_->Print("]"); } @@ -457,7 +531,7 @@ void Generator::PrintTopLevelExtensions() const { printer_->Print("$constant_name$ = $number$\n", "constant_name", constant_name, "number", SimpleItoa(extension_field.number())); - printer_->Print("$name$ = ", "name", extension_field.name()); + printer_->Print("$name$ = ", "name", FieldName(extension_field)); PrintFieldDescriptor(extension_field, is_extension); printer_->Print("\n"); } @@ -804,7 +878,7 @@ void Generator::AddExtensionToFileDescriptor( const FieldDescriptor& descriptor) const { map<string, string> m; m["descriptor_name"] = kDescriptorKey; - m["field_name"] = descriptor.name(); + m["field_name"] = FieldName(descriptor); const char file_descriptor_template[] = "$descriptor_name$.extensions_by_name['$field_name$'] = " "$field_name$\n"; @@ -857,12 +931,12 @@ string Generator::FieldReferencingExpression( GOOGLE_CHECK_EQ(field.file(), file_) << field.file()->name() << " vs. " << file_->name(); if (!containing_type) { - return field.name(); + return FieldName(field); } return strings::Substitute( "$0.$1['$2']", ModuleLevelDescriptorName(*containing_type), - python_dict_name, field.name()); + python_dict_name, FieldName(field)); } // Prints containing_type for nested descriptors or enum descriptors. @@ -991,7 +1065,7 @@ void Generator::PrintFieldDescriptor( string options_string; field.options().SerializeToString(&options_string); map<string, string> m; - m["name"] = field.name(); + m["name"] = FieldName(field); m["full_name"] = field.full_name(); m["index"] = SimpleItoa(field.index()); m["number"] = SimpleItoa(field.number()); @@ -1084,7 +1158,7 @@ string Generator::ModuleLevelDescriptorName( // We now have the name relative to its own module. Also qualify with // the module name iff this descriptor is from a different .proto file. if (descriptor.file() != file_) { - name = ModuleName(descriptor.file()->name()) + "." + name; + name = ModuleAlias(descriptor.file()->name()) + "." + name; } return name; } @@ -1096,7 +1170,7 @@ string Generator::ModuleLevelDescriptorName( string Generator::ModuleLevelMessageName(const Descriptor& descriptor) const { string name = NamePrefixedWithNestedTypes(descriptor, "."); if (descriptor.file() != file_) { - name = ModuleName(descriptor.file()->name()) + "." + name; + name = ModuleAlias(descriptor.file()->name()) + "." + name; } return name; } @@ -1109,7 +1183,7 @@ string Generator::ModuleLevelServiceDescriptorName( UpperString(&name); name = "_" + name; if (descriptor.file() != file_) { - name = ModuleName(descriptor.file()->name()) + "." + name; + name = ModuleAlias(descriptor.file()->name()) + "." + name; } return name; } @@ -1211,7 +1285,7 @@ void Generator::FixOptionsForField( if (field.is_extension()) { if (field.extension_scope() == NULL) { // Top level extensions. - field_name = field.name(); + field_name = FieldName(field); } else { field_name = FieldReferencingExpression( field.extension_scope(), field, "extensions_by_name"); @@ -1256,6 +1330,18 @@ void Generator::FixOptionsForMessage(const Descriptor& descriptor) const { } } +// If a dependency forwards other files through public dependencies, let's +// copy over the corresponding module aliases. +void Generator::CopyPublicDependenciesAliases( + const string& copy_from, const FileDescriptor* file) const { + for (int i = 0; i < file->public_dependency_count(); ++i) { + string module_alias = ModuleAlias(file->public_dependency(i)->name()); + printer_->Print("$alias$ = $copy_from$.$alias$\n", "alias", module_alias, + "copy_from", copy_from); + CopyPublicDependenciesAliases(copy_from, file->public_dependency(i)); + } +} + } // namespace python } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index f86e9ea2..7e8f58e5 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -148,6 +148,9 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { void FixOptionsForEnum(const EnumDescriptor& descriptor) const; void FixOptionsForMessage(const Descriptor& descriptor) const; + void CopyPublicDependenciesAliases( + const string& copy_from, const FileDescriptor* file) const; + // Very coarse-grained lock to ensure that Generate() is reentrant. // Guards file_, printer_ and file_descriptor_serialized_. mutable Mutex mutex_; diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc index 09dbc654..24c2f971 100644 --- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc +++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc @@ -35,6 +35,9 @@ // worth. #include <memory> +#ifndef _SHARED_PTR_H +#include <google/protobuf/stubs/shared_ptr.h> +#endif #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/command_line_interface.h> |