diff options
22 files changed, 333 insertions, 77 deletions
diff --git a/editors/proto.vim b/editors/proto.vim index 7cd1dbf2..23085a28 100644 --- a/editors/proto.vim +++ b/editors/proto.vim @@ -54,7 +54,7 @@ syn keyword pbTodo contained TODO FIXME XXX syn cluster pbCommentGrp contains=pbTodo syn keyword pbSyntax syntax import option -syn keyword pbStructure package message group +syn keyword pbStructure package message group oneof syn keyword pbRepeat optional required repeated syn keyword pbDefault default syn keyword pbExtend extend extensions to max diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java index bd9c2b55..cff1ee51 100644 --- a/java/src/main/java/com/google/protobuf/ByteString.java +++ b/java/src/main/java/com/google/protobuf/ByteString.java @@ -503,9 +503,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { /** * Internal (package private) implementation of - * @link{#copyTo(byte[],int,int,int}. + * {@link #copyTo(byte[],int,int,int)}. * It assumes that all error checking has already been performed and that - * @code{numberToCopy > 0}. + * {@code numberToCopy > 0}. */ protected abstract void copyToInternal(byte[] target, int sourceOffset, int targetOffset, int numberToCopy); @@ -700,7 +700,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { * The {@link InputStream} returned by this method is guaranteed to be * completely non-blocking. The method {@link InputStream#available()} * returns the number of bytes remaining in the stream. The methods - * {@link InputStream#read(byte[]), {@link InputStream#read(byte[],int,int)} + * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)} * and {@link InputStream#skip(long)} will read/skip as many bytes as are * available. * <p> diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java index 5ef39418..5a0de6d1 100644 --- a/java/src/main/java/com/google/protobuf/Internal.java +++ b/java/src/main/java/com/google/protobuf/Internal.java @@ -236,7 +236,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for longs. + * Helper method for implementing {@link Message#hashCode()} for longs. * @see Long#hashCode() */ public static int hashLong(long n) { @@ -244,7 +244,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for + * Helper method for implementing {@link Message#hashCode()} for * booleans. * @see Boolean#hashCode() */ @@ -253,7 +253,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for enums. + * Helper method for implementing {@link Message#hashCode()} for enums. * <p> * This is needed because {@link java.lang.Enum#hashCode()} is final, but we * need to use the field number as the hash code to ensure compatibility @@ -264,7 +264,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for + * Helper method for implementing {@link Message#hashCode()} for * enum lists. */ public static int hashEnumList(List<? extends EnumLite> list) { @@ -276,7 +276,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#equals()} for bytes field. + * Helper method for implementing {@link Message#equals(Object)} for bytes field. */ public static boolean equals(List<byte[]> a, List<byte[]> b) { if (a.size() != b.size()) return false; @@ -289,7 +289,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for bytes field. + * Helper method for implementing {@link Message#hashCode()} for bytes field. */ public static int hashCode(List<byte[]> list) { int hash = 1; @@ -300,7 +300,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for bytes field. + * Helper method for implementing {@link Message#hashCode()} for bytes field. */ public static int hashCode(byte[] bytes) { // The hash code for a byte array should be the same as the hash code for a @@ -311,7 +311,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#equals()} for bytes + * Helper method for implementing {@link Message#equals(Object)} for bytes * field. */ public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) { @@ -324,7 +324,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#equals()} for bytes + * Helper method for implementing {@link Message#equals(Object)} for bytes * field. */ public static boolean equalsByteBuffer( @@ -341,7 +341,7 @@ public class Internal { } /** - * Helper method for implementing {@link MessageLite#hashCode()} for bytes + * Helper method for implementing {@link Message#hashCode()} for bytes * field. */ public static int hashCodeByteBuffer(List<ByteBuffer> list) { @@ -355,7 +355,7 @@ public class Internal { private static final int DEFAULT_BUFFER_SIZE = 4096; /** - * Helper method for implementing {@link MessageLite#hashCode()} for bytes + * Helper method for implementing {@link Message#hashCode()} for bytes * field. */ public static int hashCodeByteBuffer(ByteBuffer bytes) { diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index 63e62fc6..4f6756ed 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -411,7 +411,8 @@ public final class TextFormat { generator.print("\""); generator.print(escapeNonAscii ? escapeText((String) value) : - escapeDoubleQuotesAndBackslashes((String) value)); + escapeDoubleQuotesAndBackslashes((String) value) + .replace("\n", "\\n")); generator.print("\""); break; diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 82f9582f..eba06ca0 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -864,15 +864,15 @@ public class TextFormatTest extends TestCase { assertEquals(message.getOptionalString(), builder.getOptionalString()); } - public void testPrintToUnicodeStringWithNewlines() { + public void testPrintToUnicodeStringWithNewlines() throws Exception { // No newlines at start and end - assertEquals("optional_string: \"test newlines\n\nin\nstring\"\n", + assertEquals("optional_string: \"test newlines\\n\\nin\\nstring\"\n", TextFormat.printToUnicodeString(TestAllTypes.newBuilder() .setOptionalString("test newlines\n\nin\nstring") .build())); // Newlines at start and end - assertEquals("optional_string: \"\ntest\nnewlines\n\nin\nstring\n\"\n", + assertEquals("optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n", TextFormat.printToUnicodeString(TestAllTypes.newBuilder() .setOptionalString("\ntest\nnewlines\n\nin\nstring\n") .build())); @@ -882,14 +882,22 @@ public class TextFormatTest extends TestCase { TextFormat.printToUnicodeString(TestAllTypes.newBuilder() .setOptionalString("") .build())); - assertEquals("optional_string: \"\n\"\n", + assertEquals("optional_string: \"\\n\"\n", TextFormat.printToUnicodeString(TestAllTypes.newBuilder() .setOptionalString("\n") .build())); - assertEquals("optional_string: \"\n\n\"\n", + assertEquals("optional_string: \"\\n\\n\"\n", TextFormat.printToUnicodeString(TestAllTypes.newBuilder() .setOptionalString("\n\n") .build())); + + // Test escaping roundtrip + TestAllTypes message = TestAllTypes.newBuilder() + .setOptionalString("\ntest\nnewlines\n\nin\nstring\n") + .build(); + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TextFormat.merge(TextFormat.printToUnicodeString(message), builder); + assertEquals(message.getOptionalString(), builder.getOptionalString()); } public void testPrintToUnicodeString_unknown() { diff --git a/src/Makefile.am b/src/Makefile.am index 815c9ae9..b88e32ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -239,6 +239,27 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_string_field.h \ google/protobuf/compiler/java/java_doc_comment.cc \ google/protobuf/compiler/java/java_doc_comment.h \ + google/protobuf/compiler/javanano/javanano_enum.cc \ + google/protobuf/compiler/javanano/javanano_enum_field.h \ + google/protobuf/compiler/javanano/javanano_extension.cc \ + google/protobuf/compiler/javanano/javanano_field.cc \ + google/protobuf/compiler/javanano/javanano_file.cc \ + google/protobuf/compiler/javanano/javanano_generator.cc \ + google/protobuf/compiler/javanano/javanano_helpers.cc \ + google/protobuf/compiler/javanano/javanano_message.cc \ + google/protobuf/compiler/javanano/javanano_message_field.h \ + google/protobuf/compiler/javanano/javanano_params.h \ + google/protobuf/compiler/javanano/javanano_primitive_field.h \ + google/protobuf/compiler/javanano/javanano_enum_field.cc \ + google/protobuf/compiler/javanano/javanano_enum.h \ + google/protobuf/compiler/javanano/javanano_extension.h \ + google/protobuf/compiler/javanano/javanano_field.h \ + google/protobuf/compiler/javanano/javanano_file.h \ + google/protobuf/compiler/javanano/javanano_generator.h \ + google/protobuf/compiler/javanano/javanano_helpers.h \ + google/protobuf/compiler/javanano/javanano_message_field.cc \ + google/protobuf/compiler/javanano/javanano_message.h \ + google/protobuf/compiler/javanano/javanano_primitive_field.cc \ google/protobuf/compiler/python/python_generator.cc bin_PROGRAMS = protoc diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index d354c16a..1c1caf1f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -57,7 +57,7 @@ namespace cpp { class ExtensionGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit ExtensionGenerator(const FieldDescriptor* desycriptor, + explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Options& options); ~ExtensionGenerator(); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index b42f32b8..212bc3e9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -561,7 +561,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { } else { printer->Print(vars, "inline bool $classname$::has_$name$() const {\n" - " return $name$_ != NULL;\n" + " return !_is_default_instance_ && $name$_ != NULL;\n" "}\n"); } } @@ -1051,6 +1051,22 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(cached_size_decl.c_str()); need_to_emit_cached_size = false; } + } else { + // Without field presence, we need another way to disambiguate the default + // instance, because the default instance's submessage fields (if any) store + // pointers to the default instances of the submessages even when they + // aren't present. Alternatives to this approach might be to (i) use a + // tagged pointer on all message fields, setting a tag bit for "not really + // present, just default instance"; or (ii) comparing |this| against the + // return value from GeneratedMessageFactory::GetPrototype() in all + // has_$field$() calls. However, both of these options are much more + // expensive (in code size and CPU overhead) than just checking a field in + // the message. Long-term, the best solution would be to rearchitect the + // default instance design not to store pointers to submessage default + // instances, and have reflection get those some other way; but that change + // would have too much impact on proto2. + printer->Print( + "bool _is_default_instance_;\n"); } // Field members: @@ -1323,11 +1339,21 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { if (UseUnknownFieldSet(descriptor_->file())) { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _internal_metadata_));\n"); + "$classname$, _internal_metadata_),\n"); + } else { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _arena_),\n"); + } + + // is_default_instance_ offset. + if (HasFieldPresence(descriptor_->file())) { + printer->Print(vars, + " -1);\n"); } else { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _arena_));\n"); + "$classname$, _is_default_instance_));\n"); } // Handle nested types. @@ -1612,6 +1638,11 @@ GenerateSharedConstructorCode(io::Printer* printer) { "classname", classname_); printer->Indent(); + if (!HasFieldPresence(descriptor_->file())) { + printer->Print( + " _is_default_instance_ = false;\n"); + } + printer->Print(StrCat( uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", "_cached_size_ = 0;\n").c_str()); @@ -1809,6 +1840,11 @@ GenerateStructors(io::Printer* printer) { "void $classname$::InitAsDefaultInstance() {\n", "classname", classname_); + if (!HasFieldPresence(descriptor_->file())) { + printer->Print( + " _is_default_instance_ = true;\n"); + } + // The default instance needs all of its embedded message pointers // cross-linked to other default instances. We can't do this initialization // in the constructor because some other default instances may not have been diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 2f5bdaf7..9f2127bb 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> +#include <google/protobuf/compiler/javanano/javanano_generator.h> int main(int argc, char* argv[]) { @@ -57,5 +58,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--python_out", &py_generator, "Generate Python source file."); + // Java Nano + google::protobuf::compiler::javanano::JavaNanoGenerator javanano_generator; + cli.RegisterGenerator("--javanano_out", &javanano_generator, + "Generate Java Nano source file."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index f33d716c..5118de15 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -56,7 +56,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorRequest), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_), + -1); CodeGeneratorResponse_descriptor_ = file->message_type(1); static const int CodeGeneratorResponse_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), @@ -71,7 +72,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorResponse), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_), + -1); CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); static const int CodeGeneratorResponse_File_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), @@ -87,7 +89,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorResponse_File), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_), + -1); } namespace { diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index df214d44..97121fa9 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -111,7 +111,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FileDescriptorSet), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_), + -1); FileDescriptorProto_descriptor_ = file->message_type(1); static const int FileDescriptorProto_offsets_[12] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_), @@ -136,7 +137,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FileDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_), + -1); DescriptorProto_descriptor_ = file->message_type(2); static const int DescriptorProto_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), @@ -157,7 +159,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(DescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_), + -1); DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0); static const int DescriptorProto_ExtensionRange_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_), @@ -172,7 +175,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(DescriptorProto_ExtensionRange), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_), + -1); FieldDescriptorProto_descriptor_ = file->message_type(3); static const int FieldDescriptorProto_offsets_[9] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), @@ -194,7 +198,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FieldDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_), + -1); FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0); FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1); OneofDescriptorProto_descriptor_ = file->message_type(4); @@ -210,7 +215,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(OneofDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_), + -1); EnumDescriptorProto_descriptor_ = file->message_type(5); static const int EnumDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_), @@ -226,7 +232,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(EnumDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_), + -1); EnumValueDescriptorProto_descriptor_ = file->message_type(6); static const int EnumValueDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_), @@ -242,7 +249,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(EnumValueDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_), + -1); ServiceDescriptorProto_descriptor_ = file->message_type(7); static const int ServiceDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_), @@ -258,7 +266,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(ServiceDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_), + -1); MethodDescriptorProto_descriptor_ = file->message_type(8); static const int MethodDescriptorProto_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_), @@ -277,7 +286,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(MethodDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_), + -1); FileOptions_descriptor_ = file->message_type(9); static const int FileOptions_offsets_[13] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), @@ -303,7 +313,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_), sizeof(FileOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_), + -1); FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0); MessageOptions_descriptor_ = file->message_type(10); static const int MessageOptions_offsets_[5] = { @@ -322,7 +333,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_), sizeof(MessageOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_), + -1); FieldOptions_descriptor_ = file->message_type(11); static const int FieldOptions_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), @@ -341,7 +353,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_), sizeof(FieldOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_), + -1); FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); EnumOptions_descriptor_ = file->message_type(12); static const int EnumOptions_offsets_[3] = { @@ -358,7 +371,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_), sizeof(EnumOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_), + -1); EnumValueOptions_descriptor_ = file->message_type(13); static const int EnumValueOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_), @@ -373,7 +387,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_), sizeof(EnumValueOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_), + -1); ServiceOptions_descriptor_ = file->message_type(14); static const int ServiceOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_), @@ -388,7 +403,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_), sizeof(ServiceOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_), + -1); MethodOptions_descriptor_ = file->message_type(15); static const int MethodOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_), @@ -403,7 +419,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_), sizeof(MethodOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_), + -1); UninterpretedOption_descriptor_ = file->message_type(16); static const int UninterpretedOption_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_), @@ -423,7 +440,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(UninterpretedOption), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_), + -1); UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0); static const int UninterpretedOption_NamePart_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_), @@ -438,7 +456,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(UninterpretedOption_NamePart), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_), + -1); SourceCodeInfo_descriptor_ = file->message_type(17); static const int SourceCodeInfo_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_), @@ -452,7 +471,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(SourceCodeInfo), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_), + -1); SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0); static const int SourceCodeInfo_Location_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_), @@ -469,7 +489,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(SourceCodeInfo_Location), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_), + -1); } namespace { diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 565afaab..318ce6f9 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -218,6 +218,7 @@ class DynamicMessage : public Message { int oneof_case_offset; int unknown_fields_offset; int extensions_offset; + int is_default_instance_offset; // Not owned by the TypeInfo. DynamicMessageFactory* factory; // The factory that created this object. @@ -316,6 +317,11 @@ void DynamicMessage::SharedCtor() { uint32(0); } + if (type_info_->is_default_instance_offset != -1) { + *reinterpret_cast<bool*>( + OffsetToPointer(type_info_->is_default_instance_offset)) = false; + } + new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet; if (type_info_->extensions_offset != -1) { @@ -532,6 +538,14 @@ void DynamicMessage::CrossLinkPrototypes() { factory->GetPrototypeNoLock(field->message_type()); } } + + // Set as the default instance -- this affects field-presence semantics for + // proto3. + if (type_info_->is_default_instance_offset != -1) { + void* is_default_instance_ptr = + OffsetToPointer(type_info_->is_default_instance_offset); + *reinterpret_cast<bool*>(is_default_instance_ptr) = true; + } } Message* DynamicMessage::New() const { @@ -641,11 +655,24 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( size = AlignOffset(size); // Next the has_bits, which is an array of uint32s. - type_info->has_bits_offset = size; - int has_bits_array_size = - DivideRoundingUp(type->field_count(), bitsizeof(uint32)); - size += has_bits_array_size * sizeof(uint32); - size = AlignOffset(size); + if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + type_info->has_bits_offset = -1; + } else { + type_info->has_bits_offset = size; + int has_bits_array_size = + DivideRoundingUp(type->field_count(), bitsizeof(uint32)); + size += has_bits_array_size * sizeof(uint32); + size = AlignOffset(size); + } + + // The is_default_instance member, if any. + if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + type_info->is_default_instance_offset = size; + size += sizeof(bool); + size = AlignOffset(size); + } else { + type_info->is_default_instance_offset = -1; + } // The oneof_case, if any. It is an array of uint32s. if (type->oneof_decl_count() > 0) { @@ -731,7 +758,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->pool, this, type_info->size, - -1 /* arena_offset */)); + -1 /* arena_offset */, + type_info->is_default_instance_offset)); } else { type_info->reflection.reset( new GeneratedMessageReflection( @@ -744,7 +772,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->pool, this, type_info->size, - -1 /* arena_offset */)); + -1 /* arena_offset */, + type_info->is_default_instance_offset)); } // Cross link prototypes. prototype->CrossLinkPrototypes(); diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index 6353ecbf..522a092a 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -46,6 +46,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> +#include <google/protobuf/unittest_no_field_presence.pb.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -65,6 +66,8 @@ class DynamicMessageTest : public testing::Test { const Message* packed_prototype_; const Descriptor* oneof_descriptor_; const Message* oneof_prototype_; + const Descriptor* proto3_descriptor_; + const Message* proto3_prototype_; DynamicMessageTest(): factory_(&pool_) {} @@ -76,16 +79,20 @@ class DynamicMessageTest : public testing::Test { FileDescriptorProto unittest_file; FileDescriptorProto unittest_import_file; FileDescriptorProto unittest_import_public_file; + FileDescriptorProto unittest_no_field_presence_file; unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file); unittest_import::ImportMessage::descriptor()->file()->CopyTo( &unittest_import_file); unittest_import::PublicImportMessage::descriptor()->file()->CopyTo( &unittest_import_public_file); + proto2_nofieldpresence_unittest::TestAllTypes::descriptor()-> + file()->CopyTo(&unittest_no_field_presence_file); ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL); ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL); ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL); + ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != NULL); descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes"); ASSERT_TRUE(descriptor_ != NULL); @@ -105,6 +112,12 @@ class DynamicMessageTest : public testing::Test { pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2"); ASSERT_TRUE(oneof_descriptor_ != NULL); oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_); + + proto3_descriptor_ = + pool_.FindMessageTypeByName( + "proto2_nofieldpresence_unittest.TestAllTypes"); + ASSERT_TRUE(proto3_descriptor_ != NULL); + proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_); } }; @@ -233,6 +246,40 @@ TEST_F(DynamicMessageTest, Arena) { // Return without freeing: should not leak. } +TEST_F(DynamicMessageTest, Proto3) { + Message* message = proto3_prototype_->New(); + const Reflection* refl = message->GetReflection(); + const Descriptor* desc = message->GetDescriptor(); + + // Just test a single primtive and single message field here to make sure we + // are getting the no-field-presence semantics elsewhere. DynamicMessage uses + // GeneratedMessageReflection under the hood, so the rest should be fine as + // long as GMR recognizes that we're using a proto3 message. + const FieldDescriptor* optional_int32 = + desc->FindFieldByName("optional_int32"); + const FieldDescriptor* optional_msg = + desc->FindFieldByName("optional_nested_message"); + EXPECT_TRUE(optional_int32 != NULL); + EXPECT_TRUE(optional_msg != NULL); + + EXPECT_EQ(false, refl->HasField(*message, optional_int32)); + refl->SetInt32(message, optional_int32, 42); + EXPECT_EQ(true, refl->HasField(*message, optional_int32)); + refl->SetInt32(message, optional_int32, 0); + EXPECT_EQ(false, refl->HasField(*message, optional_int32)); + + EXPECT_EQ(false, refl->HasField(*message, optional_msg)); + refl->MutableMessage(message, optional_msg); + EXPECT_EQ(true, refl->HasField(*message, optional_msg)); + delete refl->ReleaseMessage(message, optional_msg); + EXPECT_EQ(false, refl->HasField(*message, optional_msg)); + + // Also ensure that the default instance handles field presence properly. + EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg)); + + delete message; +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index a20e362c..b4e98acd 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -193,7 +193,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( const DescriptorPool* descriptor_pool, MessageFactory* factory, int object_size, - int arena_offset) + int arena_offset, + int is_default_instance_offset) : descriptor_ (descriptor), default_instance_ (default_instance), offsets_ (offsets), @@ -201,6 +202,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), arena_offset_ (arena_offset), + is_default_instance_offset_(is_default_instance_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -220,7 +222,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( const DescriptorPool* descriptor_pool, MessageFactory* factory, int object_size, - int arena_offset) + int arena_offset, + int is_default_instance_offset) : descriptor_ (descriptor), default_instance_ (default_instance), default_oneof_instance_ (default_oneof_instance), @@ -230,6 +233,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), arena_offset_ (arena_offset), + is_default_instance_offset_(is_default_instance_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -1829,6 +1833,17 @@ GeneratedMessageReflection::MutableInternalMetadataWithArena( return reinterpret_cast<InternalMetadataWithArena*>(ptr); } +inline bool +GeneratedMessageReflection::GetIsDefaultInstance( + const Message& message) const { + if (is_default_instance_offset_ == kHasNoDefaultInstanceField) { + return false; + } + const void* ptr = reinterpret_cast<const uint8*>(&message) + + is_default_instance_offset_; + return *reinterpret_cast<const bool*>(ptr); +} + // Simple accessors for manipulating has_bits_. inline bool GeneratedMessageReflection::HasBit( const Message& message, const FieldDescriptor* field) const { @@ -1836,7 +1851,8 @@ inline bool GeneratedMessageReflection::HasBit( // proto3: no has-bits. All fields present except messages, which are // present only if their message-field pointer is non-NULL. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - return GetRaw<const Message*>(message, field) != NULL; + return !GetIsDefaultInstance(message) && + GetRaw<const Message*>(message, field) != NULL; } else { // Non-message field (and non-oneof, since that was handled in HasField() // before calling us), and singular (again, checked in HasField). So, this @@ -2082,7 +2098,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( const void* default_oneof_instance, int oneof_case_offset, int object_size, - int arena_offset) { + int arena_offset, + int is_default_instance_offset) { return new GeneratedMessageReflection(descriptor, default_instance, offsets, @@ -2094,7 +2111,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( DescriptorPool::generated_pool(), MessageFactory::generated_factory(), object_size, - arena_offset); + arena_offset, + is_default_instance_offset); } GeneratedMessageReflection* @@ -2106,7 +2124,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( int unknown_fields_offset, int extensions_offset, int object_size, - int arena_offset) { + int arena_offset, + int is_default_instance_offset) { return new GeneratedMessageReflection(descriptor, default_instance, offsets, @@ -2116,7 +2135,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( DescriptorPool::generated_pool(), MessageFactory::generated_factory(), object_size, - arena_offset); + arena_offset, + is_default_instance_offset); } } // namespace internal diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 306809da..4dddf6c7 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -136,7 +136,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const DescriptorPool* pool, MessageFactory* factory, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); // Similar with the construction above. Call this construction if the // message has oneof definition. @@ -173,7 +174,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const DescriptorPool* pool, MessageFactory* factory, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); ~GeneratedMessageReflection(); // Shorter-to-call helpers for the above two constructions that work if the @@ -190,7 +192,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const void* default_oneof_instance, int oneof_case_offset, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); static GeneratedMessageReflection* NewGeneratedMessageReflection( const Descriptor* descriptor, @@ -200,7 +203,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int unknown_fields_offset, int extensions_offset, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); // implements Reflection ------------------------------------------- @@ -414,8 +418,11 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int unknown_fields_offset_; int extensions_offset_; int arena_offset_; + int is_default_instance_offset_; int object_size_; + static const int kHasNoDefaultInstanceField = -1; + const DescriptorPool* descriptor_pool_; MessageFactory* message_factory_; @@ -446,6 +453,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { inline internal::InternalMetadataWithArena* MutableInternalMetadataWithArena(Message* message) const; + inline bool GetIsDefaultInstance(const Message& message) const; + inline bool HasBit(const Message& message, const FieldDescriptor* field) const; inline void SetBit(Message* message, diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index e55a6d43..f6ae3e52 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -56,7 +56,7 @@ class MapField; template <typename Key, typename T> class MapPair { public: - typedef Key first_type; + typedef const Key first_type; typedef T second_type; MapPair(const Key& other_first, const T& other_second) @@ -67,14 +67,13 @@ class MapPair { MapPair(const MapPair& other) : first(other.first), second(other.second) {} - MapPair& operator=(const MapPair& other) { - first = other.first; - second = other.second; - return *this; - } - ~MapPair() {} + // Implicitly convertible to std::pair. + operator std::pair<const Key, T>() const { + return std::pair<const Key, T>(first, second); + } + const Key first; T second; diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 4ceaf4a0..0fad1351 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -213,6 +213,13 @@ class LIBPROTOBUF_EXPORT MapField : public MapFieldBase { mutable const EntryType* default_entry_; }; +// True if IsInitialized() is true for value field in all elements of t. T is +// expected to be message. It's useful to have this helper here to keep the +// protobuf compiler from ever having to emit loops in IsInitialized() methods. +// We want the C++ compiler to inline this or not as it sees fit. +template <typename Key, typename T> +bool AllAreInitialized(const Map<Key, T>& t); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 6f17df95..79302e48 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -262,6 +262,15 @@ void MapField<Key, T, KeyProto, ValueProto, } } +template <typename Key, typename T> +bool AllAreInitialized(const Map<Key, T>& t) { + for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end(); + ++it) { + if (!it->second.IsInitialized()) return false; + } + return true; +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index f9544efb..c680ccb2 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -544,6 +544,13 @@ TEST_F(MapImplTest, EqualRange) { EXPECT_TRUE(const_map_.end() == const_range.second); } +TEST_F(MapImplTest, ConvertToStdMap) { + map_[100] = 101; + std::map<int32, int32> std_map(map_.begin(), map_.end()); + EXPECT_EQ(1, std_map.size()); + EXPECT_EQ(101, std_map[100]); +} + // Map Field Reflection Test ======================================== static int Func(int i, int j) { @@ -1740,6 +1747,20 @@ TEST(GeneratedMapFieldTest, MessageLiteMap) { EXPECT_EQ(1, to.map_field().at(1)); } +TEST(GeneratedMapFieldTest, IsInitialized) { + unittest::TestRequiredMessageMap map_message; + + // Add an uninitialized message. + (*map_message.mutable_map_field())[0]; + EXPECT_FALSE(map_message.IsInitialized()); + + // Initialize uninitialized message + (*map_message.mutable_map_field())[0].set_a(0); + (*map_message.mutable_map_field())[0].set_b(0); + (*map_message.mutable_map_field())[0].set_c(0); + EXPECT_TRUE(map_message.IsInitialized()); +} + // Generated Message Reflection Test ================================ TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index 54bc4486..9232d58f 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -75,3 +75,8 @@ enum MapEnum { MAP_ENUM_BAR = 1; MAP_ENUM_BAZ = 2; } + +// Test embeded message with required fields +message TestRequiredMessageMap { + map<int32, TestRequired> map_field = 1; +} diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc index f248327c..4b7b31d9 100644 --- a/src/google/protobuf/no_field_presence_test.cc +++ b/src/google/protobuf/no_field_presence_test.cc @@ -269,6 +269,10 @@ TEST(NoFieldPresenceTest, MessageFieldPresenceTest) { EXPECT_EQ(true, message.has_optional_lazy_message()); message.clear_optional_lazy_message(); EXPECT_EQ(false, message.has_optional_lazy_message()); + + // Test field presence of a message field on the default instance. + EXPECT_EQ(false, proto2_nofieldpresence_unittest::TestAllTypes:: + default_instance().has_optional_nested_message()); } TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { @@ -287,6 +291,13 @@ TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { EXPECT_EQ(false, r->HasField(message, field)); } + // Test field presence of a message field on the default instance. + const google::protobuf::FieldDescriptor* msg_field = + desc->FindFieldByName("optional_nested_message"); + EXPECT_EQ(false, r->HasField( + proto2_nofieldpresence_unittest::TestAllTypes:: + default_instance(), msg_field)); + // Fill all fields, expect everything to report true (check oneofs below). FillValues(&message); for (int i = 0; i < desc->field_count(); i++) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 6f7a9fdb..e8c0a13c 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -224,13 +224,16 @@ class LIBPROTOBUF_EXPORT UnknownField { uint32 number_; uint32 type_; + + union LengthDelimited { + string* string_value_; + }; + union { uint64 varint_; uint32 fixed32_; uint64 fixed64_; - mutable union { - string* string_value_; - } length_delimited_; + mutable union LengthDelimited length_delimited_; UnknownFieldSet* group_; }; }; |