From 6ef984af4b0c63c1c33127a12dcfc8e6359f0c9e Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Mon, 10 Nov 2014 17:34:54 -0800 Subject: Down-integrate from internal code base. --- Makefile.am | 25 +- java/pom.xml | 29 +- .../java/com/google/protobuf/AbstractMessage.java | 60 +- .../java/com/google/protobuf/CodedInputStream.java | 30 +- .../main/java/com/google/protobuf/Descriptors.java | 115 + .../java/com/google/protobuf/DynamicMessage.java | 27 +- .../main/java/com/google/protobuf/Extension.java | 23 +- .../java/com/google/protobuf/ExtensionLite.java | 63 + .../main/java/com/google/protobuf/FieldSet.java | 4 +- .../java/com/google/protobuf/GeneratedMessage.java | 364 ++- .../com/google/protobuf/GeneratedMessageLite.java | 319 ++- .../main/java/com/google/protobuf/Internal.java | 166 ++ .../com/google/protobuf/LazyStringArrayList.java | 4 + .../com/google/protobuf/LiteralByteString.java | 9 + .../main/java/com/google/protobuf/MapEntry.java | 433 +++ .../java/com/google/protobuf/MapEntryLite.java | 331 +++ .../main/java/com/google/protobuf/MapField.java | 259 ++ .../java/com/google/protobuf/MapFieldLite.java | 182 ++ .../src/main/java/com/google/protobuf/Message.java | 19 + .../com/google/protobuf/MessageReflection.java | 33 +- .../com/google/protobuf/RepeatedFieldBuilder.java | 24 +- .../main/java/com/google/protobuf/TextFormat.java | 14 +- .../java/com/google/protobuf/UnknownFieldSet.java | 15 + .../com/google/protobuf/UnknownFieldSetLite.java | 297 ++ .../com/google/protobuf/CodedInputStreamTest.java | 10 +- .../java/com/google/protobuf/DescriptorsTest.java | 6 + .../com/google/protobuf/FieldPresenceTest.java | 363 +++ .../com/google/protobuf/GeneratedMessageTest.java | 141 +- .../com/google/protobuf/LazyMessageLiteTest.java | 31 - .../com/google/protobuf/LiteEqualsAndHashTest.java | 23 + .../com/google/protobuf/MapForProto2LiteTest.java | 277 ++ .../java/com/google/protobuf/MapForProto2Test.java | 488 ++++ .../src/test/java/com/google/protobuf/MapTest.java | 569 ++++ .../com/google/protobuf/TestBadIdentifiers.java | 2 +- .../java/com/google/protobuf/TextFormatTest.java | 15 +- .../com/google/protobuf/UnknownEnumValueTest.java | 255 ++ .../google/protobuf/UnknownFieldSetLiteTest.java | 317 +++ .../com/google/protobuf/field_presence_test.proto | 93 + .../com/google/protobuf/lazy_fields_lite.proto | 1 + .../com/google/protobuf/lite_equals_and_hash.proto | 17 + .../google/protobuf/map_for_proto2_lite_test.proto | 63 + .../com/google/protobuf/map_for_proto2_test.proto | 62 + .../test/java/com/google/protobuf/map_test.proto | 63 + .../com/google/protobuf/multiple_files_test.proto | 1 + .../com/google/protobuf/nested_builders_test.proto | 1 + .../com/google/protobuf/nested_extension.proto | 1 + .../google/protobuf/nested_extension_lite.proto | 1 + .../com/google/protobuf/non_nested_extension.proto | 1 + .../protobuf/non_nested_extension_lite.proto | 1 + .../google/protobuf/outer_class_name_test.proto | 2 + .../google/protobuf/outer_class_name_test2.proto | 2 + .../google/protobuf/outer_class_name_test3.proto | 2 + .../com/google/protobuf/test_bad_identifiers.proto | 24 +- .../java/com/google/protobuf/test_check_utf8.proto | 1 + .../com/google/protobuf/test_check_utf8_size.proto | 1 + .../com/google/protobuf/test_custom_options.proto | 1 + .../google/protobuf/test_extra_interfaces.proto | 1 + python/google/protobuf/descriptor.py | 5 +- python/google/protobuf/descriptor_database.py | 4 +- python/google/protobuf/descriptor_pool.py | 2 +- .../protobuf/internal/descriptor_database_test.py | 2 + .../protobuf/internal/descriptor_pool_test.py | 29 +- .../protobuf/internal/descriptor_pool_test1.proto | 2 + .../protobuf/internal/descriptor_pool_test2.proto | 2 + python/google/protobuf/internal/descriptor_test.py | 10 + .../google/protobuf/internal/factory_test1.proto | 1 + .../google/protobuf/internal/factory_test2.proto | 7 + python/google/protobuf/internal/generator_test.py | 4 +- .../protobuf/internal/import_test_package/BUILD | 27 + .../internal/import_test_package/__init__.py | 33 + .../internal/import_test_package/inner.proto | 37 + .../internal/import_test_package/outer.proto | 39 + python/google/protobuf/internal/message_test.py | 40 + .../protobuf/internal/missing_enum_values.proto | 2 + .../google/protobuf/internal/more_extensions.proto | 1 + .../internal/more_extensions_dynamic.proto | 1 + .../google/protobuf/internal/more_messages.proto | 1 + .../google/protobuf/internal/proto_builder_test.py | 77 + python/google/protobuf/internal/python_message.py | 24 +- python/google/protobuf/internal/reflection_test.py | 59 +- .../protobuf/internal/test_bad_identifiers.proto | 7 +- .../google/protobuf/internal/text_format_test.py | 21 +- python/google/protobuf/internal/type_checkers.py | 9 +- .../protobuf/internal/unknown_fields_test.py | 9 +- python/google/protobuf/message.py | 15 +- python/google/protobuf/proto_builder.py | 98 + python/google/protobuf/pyext/cpp_message.py | 6 +- python/google/protobuf/pyext/descriptor.cc | 222 +- python/google/protobuf/pyext/descriptor.h | 70 +- python/google/protobuf/pyext/extension_dict.cc | 110 +- python/google/protobuf/pyext/extension_dict.h | 22 +- python/google/protobuf/pyext/message.cc | 495 ++-- python/google/protobuf/pyext/message.h | 45 +- python/google/protobuf/pyext/proto2_api_test.proto | 2 + python/google/protobuf/pyext/python.proto | 2 + .../protobuf/pyext/repeated_composite_container.cc | 135 +- .../protobuf/pyext/repeated_composite_container.h | 13 +- .../protobuf/pyext/repeated_scalar_container.cc | 102 +- .../protobuf/pyext/repeated_scalar_container.h | 12 +- python/google/protobuf/pyext/scoped_pyobject_ptr.h | 2 + python/google/protobuf/text_format.py | 8 +- python/setup.py | 3 + src/Makefile.am | 85 +- src/google/protobuf/arena.cc | 238 ++ src/google/protobuf/arena.h | 479 ++++ src/google/protobuf/arena_nc.cc | 45 + src/google/protobuf/arena_nc_test.py | 59 + src/google/protobuf/arena_unittest.cc | 972 +++++++ src/google/protobuf/arenastring.cc | 43 + src/google/protobuf/arenastring.h | 314 +++ src/google/protobuf/arenastring_unittest.cc | 112 + .../protobuf/compiler/command_line_interface.cc | 3 + .../compiler/command_line_interface_unittest.cc | 13 +- src/google/protobuf/compiler/cpp/cpp_enum.cc | 9 + src/google/protobuf/compiler/cpp/cpp_enum_field.cc | 118 +- src/google/protobuf/compiler/cpp/cpp_field.cc | 17 + src/google/protobuf/compiler/cpp/cpp_field.h | 13 + src/google/protobuf/compiler/cpp/cpp_file.cc | 17 +- src/google/protobuf/compiler/cpp/cpp_file.h | 3 + src/google/protobuf/compiler/cpp/cpp_generator.cc | 3 + src/google/protobuf/compiler/cpp/cpp_helpers.cc | 21 +- src/google/protobuf/compiler/cpp/cpp_helpers.h | 33 +- src/google/protobuf/compiler/cpp/cpp_message.cc | 1014 +++++-- src/google/protobuf/compiler/cpp/cpp_message.h | 9 +- .../protobuf/compiler/cpp/cpp_message_field.cc | 369 ++- .../protobuf/compiler/cpp/cpp_plugin_unittest.cc | 128 + .../protobuf/compiler/cpp/cpp_primitive_field.cc | 8 +- .../protobuf/compiler/cpp/cpp_string_field.cc | 538 ++-- .../protobuf/compiler/cpp/cpp_string_field.h | 1 + .../compiler/cpp/cpp_test_bad_identifiers.proto | 20 +- src/google/protobuf/compiler/cpp/cpp_unittest.cc | 3 + src/google/protobuf/compiler/importer.cc | 3 + src/google/protobuf/compiler/importer_unittest.cc | 124 +- src/google/protobuf/compiler/java/java_context.h | 3 + src/google/protobuf/compiler/java/java_enum.cc | 32 +- .../protobuf/compiler/java/java_enum_field.cc | 354 ++- .../protobuf/compiler/java/java_enum_field.h | 2 + src/google/protobuf/compiler/java/java_field.cc | 18 +- src/google/protobuf/compiler/java/java_field.h | 3 + src/google/protobuf/compiler/java/java_file.cc | 27 +- src/google/protobuf/compiler/java/java_file.h | 3 + .../protobuf/compiler/java/java_generator.cc | 7 + src/google/protobuf/compiler/java/java_helpers.cc | 20 + src/google/protobuf/compiler/java/java_helpers.h | 26 +- .../protobuf/compiler/java/java_map_field.cc | 455 +++ src/google/protobuf/compiler/java/java_map_field.h | 82 + src/google/protobuf/compiler/java/java_message.cc | 399 ++- src/google/protobuf/compiler/java/java_message.h | 1 - .../protobuf/compiler/java/java_message_field.cc | 54 +- .../protobuf/compiler/java/java_plugin_unittest.cc | 3 + .../protobuf/compiler/java/java_primitive_field.cc | 20 - .../compiler/java/java_shared_code_generator.cc | 6 +- .../compiler/java/java_shared_code_generator.h | 4 + .../protobuf/compiler/java/java_string_field.cc | 27 +- .../protobuf/compiler/mock_code_generator.cc | 3 + src/google/protobuf/compiler/parser.cc | 149 +- src/google/protobuf/compiler/parser.h | 24 +- src/google/protobuf/compiler/parser_unittest.cc | 251 +- src/google/protobuf/compiler/plugin.pb.cc | 333 ++- src/google/protobuf/compiler/plugin.pb.h | 455 +-- src/google/protobuf/compiler/plugin.proto | 1 + .../protobuf/compiler/python/python_generator.cc | 116 +- .../protobuf/compiler/python/python_generator.h | 3 + .../compiler/python/python_plugin_unittest.cc | 3 + src/google/protobuf/descriptor.cc | 719 ++++- src/google/protobuf/descriptor.h | 117 +- src/google/protobuf/descriptor.pb.cc | 2490 ++++++++++------ src/google/protobuf/descriptor.pb.h | 2974 +++++++++++++------- src/google/protobuf/descriptor.proto | 51 +- src/google/protobuf/descriptor_pb2_test.py | 6 +- src/google/protobuf/descriptor_unittest.cc | 581 ++++ src/google/protobuf/drop_unknown_fields_test.cc | 88 + src/google/protobuf/dynamic_message.cc | 79 +- src/google/protobuf/dynamic_message.h | 3 + src/google/protobuf/dynamic_message_unittest.cc | 8 + src/google/protobuf/extension_set.cc | 402 ++- src/google/protobuf/extension_set.h | 16 +- src/google/protobuf/extension_set_heavy.cc | 17 +- src/google/protobuf/extension_set_unittest.cc | 112 + .../protobuf/generated_message_reflection.cc | 458 ++- src/google/protobuf/generated_message_reflection.h | 69 +- src/google/protobuf/io/coded_stream.cc | 15 + src/google/protobuf/io/coded_stream.h | 48 +- src/google/protobuf/io/coded_stream_inl.h | 11 +- src/google/protobuf/io/coded_stream_unittest.cc | 1 + src/google/protobuf/io/gzip_stream.cc | 11 +- src/google/protobuf/io/gzip_stream.h | 1 + src/google/protobuf/io/printer.cc | 13 + src/google/protobuf/io/printer.h | 5 + .../protobuf/io/zero_copy_stream_impl_lite.cc | 1 + .../protobuf/io/zero_copy_stream_impl_lite.h | 25 + .../protobuf/io/zero_copy_stream_unittest.cc | 37 + src/google/protobuf/message.cc | 89 + src/google/protobuf/message.h | 187 +- src/google/protobuf/message_lite.cc | 22 + src/google/protobuf/message_lite.h | 23 +- src/google/protobuf/message_unittest.cc | 19 + src/google/protobuf/metadata.h | 164 ++ src/google/protobuf/new_delete_capture.cc | 121 + src/google/protobuf/new_delete_capture.h | 175 ++ src/google/protobuf/no_field_presence_test.cc | 526 ++++ src/google/protobuf/preserve_unknown_enum_test.cc | 230 ++ src/google/protobuf/proto3_arena_unittest.cc | 185 ++ src/google/protobuf/proto_cast.h | 58 + src/google/protobuf/proto_cast_test.cc | 60 + src/google/protobuf/reflection.h | 306 ++ src/google/protobuf/reflection_internal.h | 310 ++ src/google/protobuf/repeated_field.cc | 72 +- src/google/protobuf/repeated_field.h | 1103 ++++++-- src/google/protobuf/repeated_field_reflection.h | 335 +++ .../protobuf/repeated_field_reflection_unittest.cc | 518 +++- src/google/protobuf/repeated_field_unittest.cc | 69 +- src/google/protobuf/stubs/atomic_sequence_num.h | 54 + src/google/protobuf/stubs/casts.h | 123 + src/google/protobuf/stubs/common.cc | 1 + src/google/protobuf/stubs/common.h | 135 +- src/google/protobuf/stubs/common_unittest.cc | 1 + src/google/protobuf/stubs/fastmem.h | 153 + src/google/protobuf/stubs/singleton.h | 64 + src/google/protobuf/stubs/strutil.cc | 56 + src/google/protobuf/stubs/strutil.h | 32 + src/google/protobuf/stubs/type_traits.h | 39 +- src/google/protobuf/text_format.cc | 22 +- src/google/protobuf/text_format.h | 3 + src/google/protobuf/unittest.proto | 12 +- src/google/protobuf/unittest_arena.proto | 45 + src/google/protobuf/unittest_custom_options.proto | 3 +- .../protobuf/unittest_drop_unknown_fields.proto | 55 + .../protobuf/unittest_embed_optimize_for.proto | 1 + src/google/protobuf/unittest_empty.proto | 1 + .../protobuf/unittest_enormous_descriptor.proto | 1 + src/google/protobuf/unittest_import.proto | 1 + src/google/protobuf/unittest_import_lite.proto | 1 + src/google/protobuf/unittest_import_public.proto | 1 + .../protobuf/unittest_import_public_lite.proto | 1 + src/google/protobuf/unittest_lite.proto | 1 + .../protobuf/unittest_lite_imports_nonlite.proto | 1 + src/google/protobuf/unittest_mset.proto | 1 + src/google/protobuf/unittest_no_arena.proto | 199 ++ src/google/protobuf/unittest_no_arena_import.proto | 37 + .../protobuf/unittest_no_field_presence.proto | 138 + .../protobuf/unittest_no_generic_services.proto | 1 + src/google/protobuf/unittest_optimize_for.proto | 1 + .../protobuf/unittest_preserve_unknown_enum.proto | 66 + src/google/protobuf/unittest_proto3_arena.proto | 143 + src/google/protobuf/unknown_enum_impl.h | 132 + src/google/protobuf/unknown_enum_test.proto | 61 + src/google/protobuf/unknown_field_set.cc | 112 +- src/google/protobuf/unknown_field_set.h | 29 +- src/google/protobuf/unknown_field_set_unittest.cc | 7 + src/google/protobuf/wire_format.cc | 45 +- src/google/protobuf/wire_format_lite.cc | 29 +- src/google/protobuf/wire_format_lite.h | 28 +- src/google/protobuf/wire_format_lite_inl.h | 24 +- src/google/protobuf/wire_format_unittest.cc | 6 +- 255 files changed, 25099 insertions(+), 4893 deletions(-) create mode 100644 java/src/main/java/com/google/protobuf/ExtensionLite.java create mode 100644 java/src/main/java/com/google/protobuf/MapEntry.java create mode 100644 java/src/main/java/com/google/protobuf/MapEntryLite.java create mode 100644 java/src/main/java/com/google/protobuf/MapField.java create mode 100644 java/src/main/java/com/google/protobuf/MapFieldLite.java create mode 100644 java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java create mode 100644 java/src/test/java/com/google/protobuf/FieldPresenceTest.java create mode 100644 java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java create mode 100644 java/src/test/java/com/google/protobuf/MapForProto2Test.java create mode 100644 java/src/test/java/com/google/protobuf/MapTest.java create mode 100644 java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java create mode 100644 java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java create mode 100644 java/src/test/java/com/google/protobuf/field_presence_test.proto create mode 100644 java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto create mode 100644 java/src/test/java/com/google/protobuf/map_for_proto2_test.proto create mode 100644 java/src/test/java/com/google/protobuf/map_test.proto create mode 100644 python/google/protobuf/internal/import_test_package/BUILD create mode 100644 python/google/protobuf/internal/import_test_package/__init__.py create mode 100644 python/google/protobuf/internal/import_test_package/inner.proto create mode 100644 python/google/protobuf/internal/import_test_package/outer.proto create mode 100644 python/google/protobuf/internal/proto_builder_test.py create mode 100644 python/google/protobuf/proto_builder.py create mode 100644 src/google/protobuf/arena.cc create mode 100644 src/google/protobuf/arena.h create mode 100644 src/google/protobuf/arena_nc.cc create mode 100644 src/google/protobuf/arena_nc_test.py create mode 100644 src/google/protobuf/arena_unittest.cc create mode 100644 src/google/protobuf/arenastring.cc create mode 100755 src/google/protobuf/arenastring.h create mode 100644 src/google/protobuf/arenastring_unittest.cc create mode 100644 src/google/protobuf/compiler/java/java_map_field.cc create mode 100644 src/google/protobuf/compiler/java/java_map_field.h create mode 100644 src/google/protobuf/drop_unknown_fields_test.cc create mode 100644 src/google/protobuf/metadata.h create mode 100644 src/google/protobuf/new_delete_capture.cc create mode 100644 src/google/protobuf/new_delete_capture.h create mode 100644 src/google/protobuf/no_field_presence_test.cc create mode 100644 src/google/protobuf/preserve_unknown_enum_test.cc create mode 100644 src/google/protobuf/proto3_arena_unittest.cc create mode 100644 src/google/protobuf/proto_cast.h create mode 100644 src/google/protobuf/proto_cast_test.cc create mode 100644 src/google/protobuf/reflection.h create mode 100644 src/google/protobuf/reflection_internal.h create mode 100644 src/google/protobuf/repeated_field_reflection.h create mode 100644 src/google/protobuf/stubs/atomic_sequence_num.h create mode 100644 src/google/protobuf/stubs/casts.h create mode 100644 src/google/protobuf/stubs/fastmem.h create mode 100644 src/google/protobuf/stubs/singleton.h create mode 100644 src/google/protobuf/unittest_arena.proto create mode 100644 src/google/protobuf/unittest_drop_unknown_fields.proto create mode 100644 src/google/protobuf/unittest_no_arena.proto create mode 100644 src/google/protobuf/unittest_no_arena_import.proto create mode 100644 src/google/protobuf/unittest_no_field_presence.proto create mode 100644 src/google/protobuf/unittest_preserve_unknown_enum.proto create mode 100644 src/google/protobuf/unittest_proto3_arena.proto create mode 100644 src/google/protobuf/unknown_enum_impl.h create mode 100644 src/google/protobuf/unknown_enum_test.proto diff --git a/Makefile.am b/Makefile.am index 24e5e55c..4a29e1cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -79,6 +79,7 @@ EXTRA_DIST = \ java/src/main/java/com/google/protobuf/Descriptors.java \ java/src/main/java/com/google/protobuf/DynamicMessage.java \ java/src/main/java/com/google/protobuf/Extension.java \ + java/src/main/java/com/google/protobuf/ExtensionLite.java \ java/src/main/java/com/google/protobuf/ExtensionRegistry.java \ java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \ java/src/main/java/com/google/protobuf/FieldSet.java \ @@ -91,6 +92,10 @@ EXTRA_DIST = \ java/src/main/java/com/google/protobuf/LazyStringArrayList.java \ java/src/main/java/com/google/protobuf/LazyStringList.java \ java/src/main/java/com/google/protobuf/LiteralByteString.java \ + java/src/main/java/com/google/protobuf/MapEntry.java \ + java/src/main/java/com/google/protobuf/MapEntryLite.java \ + java/src/main/java/com/google/protobuf/MapField.java \ + java/src/main/java/com/google/protobuf/MapFieldLite.java \ java/src/main/java/com/google/protobuf/Message.java \ java/src/main/java/com/google/protobuf/MessageLite.java \ java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java \ @@ -112,6 +117,7 @@ EXTRA_DIST = \ java/src/main/java/com/google/protobuf/TextFormat.java \ java/src/main/java/com/google/protobuf/UninitializedMessageException.java \ java/src/main/java/com/google/protobuf/UnknownFieldSet.java \ + java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java \ java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java \ java/src/main/java/com/google/protobuf/Utf8.java \ java/src/main/java/com/google/protobuf/WireFormat.java \ @@ -124,18 +130,22 @@ EXTRA_DIST = \ java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java \ java/src/test/java/com/google/protobuf/DescriptorsTest.java \ java/src/test/java/com/google/protobuf/DynamicMessageTest.java \ + java/src/test/java/com/google/protobuf/FieldPresenceTest.java \ java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java \ java/src/test/java/com/google/protobuf/GeneratedMessageTest.java \ java/src/test/java/com/google/protobuf/IsValidUtf8Test.java \ java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java \ - java/src/test/java/com/google/protobuf/LazyFieldTest.java \ java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java \ + java/src/test/java/com/google/protobuf/LazyFieldTest.java \ java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java \ java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java \ java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java \ java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java \ java/src/test/java/com/google/protobuf/LiteralByteStringTest.java \ java/src/test/java/com/google/protobuf/LiteTest.java \ + java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java \ + java/src/test/java/com/google/protobuf/MapForProto2Test.java \ + java/src/test/java/com/google/protobuf/MapTest.java \ java/src/test/java/com/google/protobuf/MessageTest.java \ java/src/test/java/com/google/protobuf/NestedBuildersTest.java \ java/src/test/java/com/google/protobuf/ParserTest.java \ @@ -148,20 +158,25 @@ EXTRA_DIST = \ java/src/test/java/com/google/protobuf/TestBadIdentifiers.java \ java/src/test/java/com/google/protobuf/TestUtil.java \ java/src/test/java/com/google/protobuf/TextFormatTest.java \ + java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java \ + java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java \ java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java \ java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java \ java/src/test/java/com/google/protobuf/WireFormatTest.java \ + java/src/test/java/com/google/protobuf/field_presence_test.proto \ java/src/test/java/com/google/protobuf/lazy_fields_lite.proto \ java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto \ + java/src/test/java/com/google/protobuf/map_for_proto2_test.proto \ + java/src/test/java/com/google/protobuf/map_test.proto \ java/src/test/java/com/google/protobuf/multiple_files_test.proto \ java/src/test/java/com/google/protobuf/nested_builders_test.proto \ java/src/test/java/com/google/protobuf/nested_extension_lite.proto \ java/src/test/java/com/google/protobuf/nested_extension.proto \ java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto \ java/src/test/java/com/google/protobuf/non_nested_extension.proto \ - java/src/test/java/com/google/protobuf/outer_class_name_test.proto \ java/src/test/java/com/google/protobuf/outer_class_name_test2.proto \ java/src/test/java/com/google/protobuf/outer_class_name_test3.proto \ + java/src/test/java/com/google/protobuf/outer_class_name_test.proto \ java/src/test/java/com/google/protobuf/test_bad_identifiers.proto \ java/src/test/java/com/google/protobuf/test_check_utf8.proto \ java/src/test/java/com/google/protobuf/test_check_utf8_size.proto \ @@ -194,6 +209,7 @@ EXTRA_DIST = \ python/google/protobuf/internal/more_extensions.proto \ python/google/protobuf/internal/more_extensions_dynamic.proto \ python/google/protobuf/internal/more_messages.proto \ + python/google/protobuf/internal/proto_builder_test.py \ python/google/protobuf/internal/python_message.py \ python/google/protobuf/internal/reflection_test.py \ python/google/protobuf/internal/service_reflection_test.py \ @@ -207,6 +223,10 @@ EXTRA_DIST = \ python/google/protobuf/internal/wire_format.py \ python/google/protobuf/internal/wire_format_test.py \ python/google/protobuf/internal/__init__.py \ + python/google/protobuf/internal/import_test_package/BUILD \ + python/google/protobuf/internal/import_test_package/__init__.py \ + python/google/protobuf/internal/import_test_package/inner.proto \ + python/google/protobuf/internal/import_test_package/outer.proto \ python/google/protobuf/pyext/README \ python/google/protobuf/pyext/cpp_message.py \ python/google/protobuf/pyext/descriptor.h \ @@ -232,6 +252,7 @@ EXTRA_DIST = \ python/google/protobuf/descriptor_pool.py \ python/google/protobuf/message.py \ python/google/protobuf/message_factory.py \ + python/google/protobuf/proto_builder.py \ python/google/protobuf/reflection.py \ python/google/protobuf/service.py \ python/google/protobuf/service_reflection.py \ diff --git a/java/pom.xml b/java/pom.xml index 1e3baa3c..a2bd1d1e 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -130,6 +130,10 @@ + + + + target/generated-test-sources @@ -164,34 +168,37 @@ **/AbstractMessageLite.java + **/AbstractParser.java + **/BoundedByteString.java **/ByteString.java **/CodedInputStream.java **/CodedOutputStream.java + **/ExtensionLite.java **/ExtensionRegistryLite.java **/FieldSet.java **/GeneratedMessageLite.java **/Internal.java **/InvalidProtocolBufferException.java + **/LazyFieldLite.java **/LazyStringArrayList.java **/LazyStringList.java + **/LiteralByteString.java + **/MapEntryLite.java + **/MapFieldLite.java **/MessageLite.java **/MessageLiteOrBuilder.java + **/Parser.java + **/ProtocolStringList.java + **/RopeByteString.java **/SmallSortedMap.java **/UninitializedMessageException.java + **/UnknownFieldSetLite.java **/UnmodifiableLazyStringList.java - **/WireFormat.java - **/Parser.java - **/AbstractParser.java - **/BoundedByteString.java - **/LiteralByteString.java - **/RopeByteString.java **/Utf8.java - **/LazyField.java - **/LazyFieldLite.java - **/ProtocolStringList.java + **/WireFormat.java - **/LiteTest.java + **/**LiteTest.java **/*Lite.java @@ -200,7 +207,7 @@ maven-surefire-plugin - **/LiteTest.java + **/**LiteTest.java diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java index ae9d5e39..6de4cae3 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -37,6 +37,9 @@ import com.google.protobuf.Internal.EnumLite; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -143,6 +146,40 @@ public abstract class AbstractMessage extends AbstractMessageLite return toByteString(a).equals(toByteString(b)); } + /** + * Converts a list of MapEntry messages into a Map used for equals() and + * hashCode(). + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static Map convertMapEntryListToMap(List list) { + if (list.isEmpty()) { + return Collections.emptyMap(); + } + Map result = new HashMap(); + Iterator iterator = list.iterator(); + Message entry = (Message) iterator.next(); + Descriptors.Descriptor descriptor = entry.getDescriptorForType(); + Descriptors.FieldDescriptor key = descriptor.findFieldByName("key"); + Descriptors.FieldDescriptor value = descriptor.findFieldByName("value"); + result.put(entry.getField(key), entry.getField(value)); + while (iterator.hasNext()) { + entry = (Message) iterator.next(); + result.put(entry.getField(key), entry.getField(value)); + } + return result; + } + + /** + * Compares two map fields. The parameters must be a list of MapEntry + * messages. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static boolean compareMapField(Object a, Object b) { + Map ma = convertMapEntryListToMap((List) a); + Map mb = convertMapEntryListToMap((List) b); + return MapFieldLite.equals(ma, mb); + } + /** * Compares two set of fields. * This method is used to implement {@link AbstractMessage#equals(Object)} @@ -181,6 +218,10 @@ public abstract class AbstractMessage extends AbstractMessageLite return false; } } + } else if (descriptor.isMapField()) { + if (!compareMapField(value1, value2)) { + return false; + } } else { // Compare non-bytes fields. if (!value1.equals(value2)) { @@ -190,6 +231,15 @@ public abstract class AbstractMessage extends AbstractMessageLite } return true; } + + /** + * Calculates the hash code of a map field. {@code value} must be a list of + * MapEntry messages. + */ + @SuppressWarnings("unchecked") + private static int hashMapField(Object value) { + return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value)); + } /** Get a hash code for given fields and values, using the given seed. */ @SuppressWarnings("unchecked") @@ -198,7 +248,9 @@ public abstract class AbstractMessage extends AbstractMessageLite FieldDescriptor field = entry.getKey(); Object value = entry.getValue(); hash = (37 * hash) + field.getNumber(); - if (field.getType() != FieldDescriptor.Type.ENUM){ + if (field.isMapField()) { + hash = (53 * hash) + hashMapField(value); + } else if (field.getType() != FieldDescriptor.Type.ENUM){ hash = (53 * hash) + value.hashCode(); } else if (field.isRepeated()) { List list = (List) value; @@ -359,6 +411,12 @@ public abstract class AbstractMessage extends AbstractMessageLite "getFieldBuilder() called on an unsupported message type."); } + public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, + int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldBuilder() called on an unsupported message type."); + } + public String toString() { return TextFormat.printToString(this); } diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java index a00ae86f..0ca00bab 100644 --- a/java/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java @@ -612,16 +612,16 @@ public final class CodedInputStream { return x; } else if (bufferSize - pos < 9) { break fastpath; - } else if ((x ^= (buffer[pos++] << 7)) < 0L) { - x ^= (~0L << 7); - } else if ((x ^= (buffer[pos++] << 14)) >= 0L) { - x ^= (~0L << 7) ^ (~0L << 14); - } else if ((x ^= (buffer[pos++] << 21)) < 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21); + } else if ((x ^= (buffer[pos++] << 7)) < 0) { + x ^= (~0 << 7); + } else if ((x ^= (buffer[pos++] << 14)) >= 0) { + x ^= (~0 << 7) ^ (~0 << 14); + } else if ((x ^= (buffer[pos++] << 21)) < 0) { + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); } else { int y = buffer[pos++]; x ^= y << 28; - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); if (y < 0 && buffer[pos++] < 0 && buffer[pos++] < 0 && @@ -739,13 +739,13 @@ public final class CodedInputStream { return y; } else if (bufferSize - pos < 9) { break fastpath; - } else if ((x = y ^ (buffer[pos++] << 7)) < 0L) { - x ^= (~0L << 7); - } else if ((x ^= (buffer[pos++] << 14)) >= 0L) { - x ^= (~0L << 7) ^ (~0L << 14); - } else if ((x ^= (buffer[pos++] << 21)) < 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21); - } else if ((x ^= ((long) buffer[pos++] << 28)) >= 0L) { + } else if ((y ^= (buffer[pos++] << 7)) < 0) { + x = y ^ (~0 << 7); + } else if ((y ^= (buffer[pos++] << 14)) >= 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14)); + } else if ((y ^= (buffer[pos++] << 21)) < 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); + } else if ((x = ((long) y) ^ ((long) buffer[pos++] << 28)) >= 0L) { x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) { x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); @@ -882,7 +882,7 @@ public final class CodedInputStream { /** See setSizeLimit() */ private int sizeLimit = DEFAULT_SIZE_LIMIT; - private static final int DEFAULT_RECURSION_LIMIT = 64; + private static final int DEFAULT_RECURSION_LIMIT = 100; private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB private static final int BUFFER_SIZE = 4096; diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index caae0f77..d65e8b49 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -32,6 +32,7 @@ package com.google.protobuf; import com.google.protobuf.DescriptorProtos.*; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -40,6 +41,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import java.util.logging.Logger; import java.io.UnsupportedEncodingException; @@ -123,6 +125,26 @@ public final class Descriptors { return Collections.unmodifiableList(Arrays.asList(publicDependencies)); } + /** The syntax of the .proto file. */ + public enum Syntax { + UNKNOWN("unknown"), + PROTO2("proto2"), + PROTO3("proto3"); + + Syntax(String name) { + this.name = name; + } + private final String name; + } + + /** Get the syntax of the .proto file. */ + public Syntax getSyntax() { + if (Syntax.PROTO3.name.equals(proto.getSyntax())) { + return Syntax.PROTO3; + } + return Syntax.PROTO2; + } + /** * Find a message type in the file by name. Does not find nested types. * @@ -539,6 +561,10 @@ public final class Descriptors { extensions[i].setProto(proto.getExtension(i)); } } + + boolean supportsUnknownEnumValue() { + return getSyntax() == Syntax.PROTO3; + } } // ================================================================= @@ -871,6 +897,11 @@ public final class Descriptors { return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8()); } + boolean isMapField() { + return getType() == Type.MESSAGE && isRepeated() + && getMessageType().getOptions().getMapEntry(); + } + // I'm pretty sure values() constructs a new array every time, since there // is nothing stopping the caller from mutating the array. Therefore we // make a static copy here. @@ -1001,6 +1032,11 @@ public final class Descriptors { return getNumber() - other.getNumber(); } + @Override + public String toString() { + return getFullName(); + } + private final int index; private FieldDescriptorProto proto; @@ -1420,6 +1456,64 @@ public final class Descriptors { return file.pool.enumValuesByNumber.get( new DescriptorPool.DescriptorIntPair(this, number)); } + + /** + * Get the enum value for a number. If no enum value has this number, + * construct an EnumValueDescriptor for it. + */ + public EnumValueDescriptor findValueByNumberCreatingIfUnknown(final int number) { + EnumValueDescriptor result = findValueByNumber(number); + if (result != null) { + return result; + } + // The number represents an unknown enum value. + synchronized (this) { + // Descriptors are compared by object identity so for the same number + // we need to return the same EnumValueDescriptor object. This means + // we have to store created EnumValueDescriptors. However, as there + // are potentially 2G unknown enum values, storing all of these + // objects persistently will consume lots of memory for long-running + // services and it's also unnecessary as not many EnumValueDescriptors + // will be used at the same time. + // + // To solve the problem we take advantage of Java's weak references and + // rely on gc to release unused descriptors. + // + // Here is how it works: + // * We store unknown EnumValueDescriptors in a WeakHashMap with the + // value being a weak reference to the descriptor. + // * The descriptor holds a strong reference to the key so as long + // as the EnumValueDescriptor is in use, the key will be there + // and the corresponding map entry will be there. Following-up + // queries with the same number will return the same descriptor. + // * If the user no longer uses an unknown EnumValueDescriptor, + // it will be gc-ed since we only hold a weak reference to it in + // the map. The key in the corresponding map entry will also be + // gc-ed as the only strong reference to it is in the descriptor + // which is just gc-ed. With the key being gone WeakHashMap will + // then remove the whole entry. This way unknown descriptors will + // be freed automatically and we don't need to do anything to + // clean-up unused map entries. + + // Note: We must use "new Integer(number)" here because we don't want + // these Integer objects to be cached. + Integer key = new Integer(number); + WeakReference reference = unknownValues.get(key); + if (reference != null) { + result = reference.get(); + } + if (result == null) { + result = new EnumValueDescriptor(file, this, key); + unknownValues.put(key, new WeakReference(result)); + } + } + return result; + } + + // Used in tests only. + int getUnknownEnumValueDescriptorCount() { + return unknownValues.size(); + } private final int index; private EnumDescriptorProto proto; @@ -1427,6 +1521,8 @@ public final class Descriptors { private final FileDescriptor file; private final Descriptor containingType; private EnumValueDescriptor[] values; + private final WeakHashMap> unknownValues = + new WeakHashMap>(); private EnumDescriptor(final EnumDescriptorProto proto, final FileDescriptor file, @@ -1531,6 +1627,25 @@ public final class Descriptors { file.pool.addSymbol(this); file.pool.addEnumValueByNumber(this); } + + private Integer number; + // Create an unknown enum value. + private EnumValueDescriptor( + final FileDescriptor file, + final EnumDescriptor parent, + final Integer number) { + String name = "UNKNOWN_ENUM_VALUE_" + parent.getName() + "_" + number; + EnumValueDescriptorProto proto = EnumValueDescriptorProto + .newBuilder().setName(name).setNumber(number).build(); + this.index = -1; + this.proto = proto; + this.file = file; + this.type = parent; + this.fullName = parent.getFullName() + '.' + proto.getName(); + this.number = number; + + // Don't add this descriptor into pool. + } /** See {@link FileDescriptor#setProto}. */ private void setProto(final EnumValueDescriptorProto proto) { diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java index c9ce667b..06b30fff 100644 --- a/java/src/main/java/com/google/protobuf/DynamicMessage.java +++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java @@ -549,12 +549,22 @@ public final class DynamicMessage extends AbstractMessage { } public Builder setUnknownFields(UnknownFieldSet unknownFields) { + if (getDescriptorForType().getFile().getSyntax() + == Descriptors.FileDescriptor.Syntax.PROTO3) { + // Proto3 discards unknown fields. + return this; + } this.unknownFields = unknownFields; return this; } @Override public Builder mergeUnknownFields(UnknownFieldSet unknownFields) { + if (getDescriptorForType().getFile().getSyntax() + == Descriptors.FileDescriptor.Syntax.PROTO3) { + // Proto3 discards unknown fields. + return this; + } this.unknownFields = UnknownFieldSet.newBuilder(this.unknownFields) .mergeFrom(unknownFields) @@ -588,10 +598,12 @@ public final class DynamicMessage extends AbstractMessage { throw new IllegalArgumentException( "DynamicMessage should use EnumValueDescriptor to set Enum Value."); } - if (field.getEnumType() != ((EnumValueDescriptor) value).getType()) { - throw new IllegalArgumentException( - "EnumValueDescriptor doesn't much Enum Field."); - } + // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not + // set incorrect EnumValueDescriptors. + // if (field.getEnumType() != ((EnumValueDescriptor) value).getType()) { + // throw new IllegalArgumentException( + // "EnumValueDescriptor doesn't match Enum Field."); + // } } /** Verifies the value for an enum field. */ @@ -618,5 +630,12 @@ public final class DynamicMessage extends AbstractMessage { throw new UnsupportedOperationException( "getFieldBuilder() called on a dynamic message type."); } + + @Override + public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(FieldDescriptor field, + int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldBuilder() called on a dynamic message type."); + } } } diff --git a/java/src/main/java/com/google/protobuf/Extension.java b/java/src/main/java/com/google/protobuf/Extension.java index 0baa22b3..68d29f33 100644 --- a/java/src/main/java/com/google/protobuf/Extension.java +++ b/java/src/main/java/com/google/protobuf/Extension.java @@ -35,27 +35,16 @@ package com.google.protobuf; * * @author liujisi@google.com (Jisi Liu) */ -public abstract class Extension { - /** Returns the field number of the extension. */ - public abstract int getNumber(); - - /** Returns the type of the field. */ - public abstract WireFormat.FieldType getLiteType(); - - /** Returns whether it is a repeated field. */ - public abstract boolean isRepeated(); +public abstract class Extension + extends ExtensionLite { /** Returns the descriptor of the extension. */ public abstract Descriptors.FieldDescriptor getDescriptor(); - /** Returns the default value of the extension field. */ - public abstract Type getDefaultValue(); - - /** - * Returns the default instance of the extension field, if it's a message - * extension. - */ - public abstract MessageLite getMessageDefaultInstance(); + /** Returns whether or not this extension is a Lite Extension. */ + final boolean isLite() { + return false; + } // All the methods below are extension implementation details. diff --git a/java/src/main/java/com/google/protobuf/ExtensionLite.java b/java/src/main/java/com/google/protobuf/ExtensionLite.java new file mode 100644 index 00000000..f8f5bd2c --- /dev/null +++ b/java/src/main/java/com/google/protobuf/ExtensionLite.java @@ -0,0 +1,63 @@ +// 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. + +package com.google.protobuf; + +/** + * Lite interface that generated extensions implement. + *

+ * Methods are for use by generated code only. You can hold a reference to + * extensions using this type name. + */ +public abstract class ExtensionLite { + + /** Returns the field number of the extension. */ + public abstract int getNumber(); + + /** Returns the type of the field. */ + public abstract WireFormat.FieldType getLiteType(); + + /** Returns whether it is a repeated field. */ + public abstract boolean isRepeated(); + + /** Returns the default value of the extension field. */ + public abstract Type getDefaultValue(); + + /** + * Returns the default instance of the extension field, if it's a message + * extension. + */ + public abstract MessageLite getMessageDefaultInstance(); + + /** Returns whether or not this extension is a Lite Extension. */ + boolean isLite() { + return true; + } +} diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java index 392f4efc..ff9b5bc0 100644 --- a/java/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/src/main/java/com/google/protobuf/FieldSet.java @@ -672,7 +672,7 @@ final class FieldSet builder) { + unknownFields = builder.getUnknownFields(); } public Parser getParserForType() { @@ -291,13 +300,12 @@ public abstract class GeneratedMessage extends AbstractMessage return isClean; } - // This is implemented here only to work around an apparent bug in the - // Java compiler and/or build system. See bug #1898463. The mere presence - // of this dummy clone() implementation makes it go away. @Override public BuilderType clone() { - throw new UnsupportedOperationException( - "This is supposed to be overridden by subclasses."); + BuilderType builder = + (BuilderType) getDefaultInstanceForType().newBuilderForType(); + builder.mergeFrom(buildPartial()); + return builder; } /** @@ -357,6 +365,13 @@ public abstract class GeneratedMessage extends AbstractMessage return internalGetFieldAccessorTable().getField(field).getBuilder(this); } + //@Override (Java 1.6 override semantics, but we must support 1.5) + public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, + int index) { + return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder( + this, index); + } + //@Override (Java 1.6 override semantics, but we must support 1.5) public boolean hasOneof(final OneofDescriptor oneof) { return internalGetFieldAccessorTable().getOneof(oneof).has(this); @@ -428,7 +443,7 @@ public abstract class GeneratedMessage extends AbstractMessage return (BuilderType) this; } - public final BuilderType setUnknownFields( + public BuilderType setUnknownFields( final UnknownFieldSet unknownFields) { this.unknownFields = unknownFields; onChanged(); @@ -436,7 +451,7 @@ public abstract class GeneratedMessage extends AbstractMessage } @Override - public final BuilderType mergeUnknownFields( + public BuilderType mergeUnknownFields( final UnknownFieldSet unknownFields) { this.unknownFields = UnknownFieldSet.newBuilder(this.unknownFields) @@ -529,6 +544,25 @@ public abstract class GeneratedMessage extends AbstractMessage isClean = false; } } + + /** + * Gets the map field with the given field number. This method should be + * overridden in the generated message class if the message contains map + * fields. + * + * Unlike other field types, reflection support for map fields can't be + * implemented based on generated public API because we need to access a + * map field as a list in reflection API but the generated API only allows + * us to access it as a map. This method returns the underlying map field + * directly and thus enables us to access the map field as a list. + */ + @SuppressWarnings({"unused", "rawtypes"}) + protected MapField internalGetMapField(int fieldNumber) { + // Note that we can't use descriptor names here because this method will + // be called when descriptor is being initialized. + throw new RuntimeException( + "No map fields found in " + getClass().getName()); + } } // ================================================================= @@ -541,19 +575,19 @@ public abstract class GeneratedMessage extends AbstractMessage /** Check if a singular extension is present. */ boolean hasExtension( - Extension extension); + ExtensionLite extension); /** Get the number of elements in a repeated extension. */ int getExtensionCount( - Extension> extension); + ExtensionLite> extension); /** Get the value of an extension. */ Type getExtension( - Extension extension); + ExtensionLite extension); /** Get one element of a repeated extension. */ Type getExtension( - Extension> extension, + ExtensionLite> extension, int index); } @@ -625,7 +659,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Check if a singular extension is present. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final boolean hasExtension( - final Extension extension) { + final ExtensionLite extensionLite) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); return extensions.hasField(extension.getDescriptor()); } @@ -633,7 +669,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Get the number of elements in a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final int getExtensionCount( - final Extension> extension) { + final ExtensionLite> extensionLite) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); final FieldDescriptor descriptor = extension.getDescriptor(); return extensions.getRepeatedFieldCount(descriptor); @@ -643,7 +681,9 @@ public abstract class GeneratedMessage extends AbstractMessage //@Override (Java 1.6 override semantics, but we must support 1.5) @SuppressWarnings("unchecked") public final Type getExtension( - final Extension extension) { + final ExtensionLite extensionLite) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); FieldDescriptor descriptor = extension.getDescriptor(); final Object value = extensions.getField(descriptor); @@ -666,8 +706,10 @@ public abstract class GeneratedMessage extends AbstractMessage //@Override (Java 1.6 override semantics, but we must support 1.5) @SuppressWarnings("unchecked") public final Type getExtension( - final Extension> extension, + final ExtensionLite> extensionLite, final int index) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); FieldDescriptor descriptor = extension.getDescriptor(); return (Type) extension.singularFromReflectionType( @@ -914,11 +956,10 @@ public abstract class GeneratedMessage extends AbstractMessage // This is implemented here only to work around an apparent bug in the // Java compiler and/or build system. See bug #1898463. The mere presence - // of this dummy clone() implementation makes it go away. + // of this clone() implementation makes it go away. @Override public BuilderType clone() { - throw new UnsupportedOperationException( - "This is supposed to be overridden by subclasses."); + return super.clone(); } private void ensureExtensionsIsMutable() { @@ -943,7 +984,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Check if a singular extension is present. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final boolean hasExtension( - final Extension extension) { + final ExtensionLite extensionLite) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); return extensions.hasField(extension.getDescriptor()); } @@ -951,7 +994,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Get the number of elements in a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final int getExtensionCount( - final Extension> extension) { + final ExtensionLite> extensionLite) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); final FieldDescriptor descriptor = extension.getDescriptor(); return extensions.getRepeatedFieldCount(descriptor); @@ -960,7 +1005,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Get the value of an extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final Type getExtension( - final Extension extension) { + final ExtensionLite extensionLite) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); FieldDescriptor descriptor = extension.getDescriptor(); final Object value = extensions.getField(descriptor); @@ -982,8 +1029,10 @@ public abstract class GeneratedMessage extends AbstractMessage /** Get one element of a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final Type getExtension( - final Extension> extension, + final ExtensionLite> extensionLite, final int index) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); FieldDescriptor descriptor = extension.getDescriptor(); return (Type) extension.singularFromReflectionType( @@ -992,8 +1041,10 @@ public abstract class GeneratedMessage extends AbstractMessage /** Set the value of an extension. */ public final BuilderType setExtension( - final Extension extension, + final ExtensionLite extensionLite, final Type value) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); ensureExtensionsIsMutable(); final FieldDescriptor descriptor = extension.getDescriptor(); @@ -1004,8 +1055,10 @@ public abstract class GeneratedMessage extends AbstractMessage /** Set the value of one element of a repeated extension. */ public final BuilderType setExtension( - final Extension> extension, + final ExtensionLite> extensionLite, final int index, final Type value) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); ensureExtensionsIsMutable(); final FieldDescriptor descriptor = extension.getDescriptor(); @@ -1018,8 +1071,10 @@ public abstract class GeneratedMessage extends AbstractMessage /** Append a value to a repeated extension. */ public final BuilderType addExtension( - final Extension> extension, + final ExtensionLite> extensionLite, final Type value) { + Extension> extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); ensureExtensionsIsMutable(); final FieldDescriptor descriptor = extension.getDescriptor(); @@ -1031,7 +1086,9 @@ public abstract class GeneratedMessage extends AbstractMessage /** Clear an extension. */ public final BuilderType clearExtension( - final Extension extension) { + final ExtensionLite extensionLite) { + Extension extension = checkNotLite(extensionLite); + verifyExtensionContainingType(extension); ensureExtensionsIsMutable(); extensions.clearField(extension.getDescriptor()); @@ -1594,6 +1651,25 @@ public abstract class GeneratedMessage extends AbstractMessage } } } + + /** + * Gets the map field with the given field number. This method should be + * overridden in the generated message class if the message contains map + * fields. + * + * Unlike other field types, reflection support for map fields can't be + * implemented based on generated public API because we need to access a + * map field as a list in reflection API but the generated API only allows + * us to access it as a map. This method returns the underlying map field + * directly and thus enables us to access the map field as a list. + */ + @SuppressWarnings({"rawtypes", "unused"}) + protected MapField internalGetMapField(int fieldNumber) { + // Note that we can't use descriptor names here because this method will + // be called when descriptor is being initialized. + throw new RuntimeException( + "No map fields found in " + getClass().getName()); + } /** * Users should ignore this class. This class provides the implementation @@ -1633,6 +1709,11 @@ public abstract class GeneratedMessage extends AbstractMessage oneofs = new OneofAccessor[descriptor.getOneofs().size()]; initialized = false; } + + private boolean isMapFieldEnabled(FieldDescriptor field) { + boolean result = true; + return result; + } /** * Ensures the field accessors are initialized. This method is thread-safe. @@ -1657,8 +1738,13 @@ public abstract class GeneratedMessage extends AbstractMessage } if (field.isRepeated()) { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { - fields[i] = new RepeatedMessageFieldAccessor( - field, camelCaseNames[i], messageClass, builderClass); + if (field.isMapField() && isMapFieldEnabled(field)) { + fields[i] = new MapFieldAccessor( + field, camelCaseNames[i], messageClass, builderClass); + } else { + fields[i] = new RepeatedMessageFieldAccessor( + field, camelCaseNames[i], messageClass, builderClass); + } } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) { fields[i] = new RepeatedEnumFieldAccessor( field, camelCaseNames[i], messageClass, builderClass); @@ -1744,6 +1830,8 @@ public abstract class GeneratedMessage extends AbstractMessage void clear(Builder builder); Message.Builder newBuilder(); Message.Builder getBuilder(GeneratedMessage.Builder builder); + Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, + int index); } /** OneofAccessor provides access to a single oneof. */ @@ -1799,9 +1887,9 @@ public abstract class GeneratedMessage extends AbstractMessage invokeOrDie(clearMethod, builder); } } - + private static boolean supportFieldPresence(FileDescriptor file) { - return true; + return file.getSyntax() == FileDescriptor.Syntax.PROTO2; } // --------------------------------------------------------------- @@ -1919,6 +2007,11 @@ public abstract class GeneratedMessage extends AbstractMessage throw new UnsupportedOperationException( "getFieldBuilder() called on a non-Message type."); } + public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, + int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldBuilder() called on a non-Message type."); + } } private static class RepeatedFieldAccessor implements FieldAccessor { @@ -2014,6 +2107,113 @@ public abstract class GeneratedMessage extends AbstractMessage throw new UnsupportedOperationException( "getFieldBuilder() called on a non-Message type."); } + public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, + int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldBuilder() called on a non-Message type."); + } + } + + private static class MapFieldAccessor implements FieldAccessor { + MapFieldAccessor( + final FieldDescriptor descriptor, final String camelCaseName, + final Class messageClass, + final Class builderClass) { + field = descriptor; + Method getDefaultInstanceMethod = + getMethodOrDie(messageClass, "getDefaultInstance"); + MapField defaultMapField = getMapField( + (GeneratedMessage) invokeOrDie(getDefaultInstanceMethod, null)); + mapEntryMessageDefaultInstance = + defaultMapField.getMapEntryMessageDefaultInstance(); + } + + private final FieldDescriptor field; + private final Message mapEntryMessageDefaultInstance; + + private MapField getMapField(GeneratedMessage message) { + return (MapField) message.internalGetMapField(field.getNumber()); + } + + private MapField getMapField(GeneratedMessage.Builder builder) { + return (MapField) builder.internalGetMapField(field.getNumber()); + } + + public Object get(GeneratedMessage message) { + List result = new ArrayList(); + for (int i = 0; i < getRepeatedCount(message); i++) { + result.add(getRepeated(message, i)); + } + return Collections.unmodifiableList(result); + } + + public Object get(Builder builder) { + List result = new ArrayList(); + for (int i = 0; i < getRepeatedCount(builder); i++) { + result.add(getRepeated(builder, i)); + } + return Collections.unmodifiableList(result); + } + + public void set(Builder builder, Object value) { + clear(builder); + for (Object entry : (List) value) { + addRepeated(builder, entry); + } + } + + public Object getRepeated(GeneratedMessage message, int index) { + return getMapField(message).getList().get(index); + } + + public Object getRepeated(Builder builder, int index) { + return getMapField(builder).getList().get(index); + } + + public void setRepeated(Builder builder, int index, Object value) { + getMapField(builder).getMutableList().set(index, (Message) value); + } + + public void addRepeated(Builder builder, Object value) { + getMapField(builder).getMutableList().add((Message) value); + } + + public boolean has(GeneratedMessage message) { + throw new UnsupportedOperationException( + "hasField() is not supported for repeated fields."); + } + + public boolean has(Builder builder) { + throw new UnsupportedOperationException( + "hasField() is not supported for repeated fields."); + } + + public int getRepeatedCount(GeneratedMessage message) { + return getMapField(message).getList().size(); + } + + public int getRepeatedCount(Builder builder) { + return getMapField(builder).getList().size(); + } + + public void clear(Builder builder) { + getMapField(builder).getMutableList().clear(); + } + + public com.google.protobuf.Message.Builder newBuilder() { + return mapEntryMessageDefaultInstance.newBuilderForType(); + } + + public com.google.protobuf.Message.Builder getBuilder(Builder builder) { + throw new UnsupportedOperationException( + "Nested builder not supported for map fields."); + } + + public com.google.protobuf.Message.Builder getRepeatedBuilder( + Builder builder, int index) { + throw new UnsupportedOperationException( + "Nested builder not supported for map fields."); + } } // --------------------------------------------------------------- @@ -2026,28 +2226,60 @@ public abstract class GeneratedMessage extends AbstractMessage final Class builderClass, final String containingOneofCamelCaseName) { super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName); + + enumDescriptor = descriptor.getEnumType(); valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class); getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor"); + + supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue(); + if (supportUnknownEnumValue) { + getValueMethod = + getMethodOrDie(messageClass, "get" + camelCaseName + "Value"); + getValueMethodBuilder = + getMethodOrDie(builderClass, "get" + camelCaseName + "Value"); + setValueMethod = + getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class); + } } + + private EnumDescriptor enumDescriptor; private Method valueOfMethod; private Method getValueDescriptorMethod; + + private boolean supportUnknownEnumValue; + private Method getValueMethod; + private Method getValueMethodBuilder; + private Method setValueMethod; @Override public Object get(final GeneratedMessage message) { + if (supportUnknownEnumValue) { + int value = (Integer) invokeOrDie(getValueMethod, message); + return enumDescriptor.findValueByNumberCreatingIfUnknown(value); + } return invokeOrDie(getValueDescriptorMethod, super.get(message)); } @Override public Object get(final GeneratedMessage.Builder builder) { + if (supportUnknownEnumValue) { + int value = (Integer) invokeOrDie(getValueMethodBuilder, builder); + return enumDescriptor.findValueByNumberCreatingIfUnknown(value); + } return invokeOrDie(getValueDescriptorMethod, super.get(builder)); } @Override public void set(final Builder builder, final Object value) { + if (supportUnknownEnumValue) { + invokeOrDie(setValueMethod, builder, + ((EnumValueDescriptor) value).getNumber()); + return; + } super.set(builder, invokeOrDie(valueOfMethod, null, value)); } } @@ -2059,22 +2291,44 @@ public abstract class GeneratedMessage extends AbstractMessage final Class messageClass, final Class builderClass) { super(descriptor, camelCaseName, messageClass, builderClass); + + enumDescriptor = descriptor.getEnumType(); valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class); getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor"); + + supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue(); + if (supportUnknownEnumValue) { + getRepeatedValueMethod = + getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class); + getRepeatedValueMethodBuilder = + getMethodOrDie(builderClass, "get" + camelCaseName + "Value", int.class); + setRepeatedValueMethod = + getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class, int.class); + addRepeatedValueMethod = + getMethodOrDie(builderClass, "add" + camelCaseName + "Value", int.class); + } } + private EnumDescriptor enumDescriptor; private final Method valueOfMethod; private final Method getValueDescriptorMethod; + + private boolean supportUnknownEnumValue; + private Method getRepeatedValueMethod; + private Method getRepeatedValueMethodBuilder; + private Method setRepeatedValueMethod; + private Method addRepeatedValueMethod; @Override @SuppressWarnings("unchecked") public Object get(final GeneratedMessage message) { final List newList = new ArrayList(); - for (final Object element : (List) super.get(message)) { - newList.add(invokeOrDie(getValueDescriptorMethod, element)); + final int size = getRepeatedCount(message); + for (int i = 0; i < size; i++) { + newList.add(getRepeated(message, i)); } return Collections.unmodifiableList(newList); } @@ -2083,8 +2337,9 @@ public abstract class GeneratedMessage extends AbstractMessage @SuppressWarnings("unchecked") public Object get(final GeneratedMessage.Builder builder) { final List newList = new ArrayList(); - for (final Object element : (List) super.get(builder)) { - newList.add(invokeOrDie(getValueDescriptorMethod, element)); + final int size = getRepeatedCount(builder); + for (int i = 0; i < size; i++) { + newList.add(getRepeated(builder, i)); } return Collections.unmodifiableList(newList); } @@ -2092,23 +2347,41 @@ public abstract class GeneratedMessage extends AbstractMessage @Override public Object getRepeated(final GeneratedMessage message, final int index) { + if (supportUnknownEnumValue) { + int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index); + return enumDescriptor.findValueByNumberCreatingIfUnknown(value); + } return invokeOrDie(getValueDescriptorMethod, super.getRepeated(message, index)); } @Override public Object getRepeated(final GeneratedMessage.Builder builder, final int index) { + if (supportUnknownEnumValue) { + int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index); + return enumDescriptor.findValueByNumberCreatingIfUnknown(value); + } return invokeOrDie(getValueDescriptorMethod, super.getRepeated(builder, index)); } @Override public void setRepeated(final Builder builder, final int index, final Object value) { + if (supportUnknownEnumValue) { + invokeOrDie(setRepeatedValueMethod, builder, index, + ((EnumValueDescriptor) value).getNumber()); + return; + } super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null, value)); } @Override public void addRepeated(final Builder builder, final Object value) { + if (supportUnknownEnumValue) { + invokeOrDie(addRepeatedValueMethod, builder, + ((EnumValueDescriptor) value).getNumber()); + return; + } super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value)); } } @@ -2168,9 +2441,12 @@ public abstract class GeneratedMessage extends AbstractMessage super(descriptor, camelCaseName, messageClass, builderClass); newBuilderMethod = getMethodOrDie(type, "newBuilder"); + getBuilderMethodBuilder = getMethodOrDie(builderClass, + "get" + camelCaseName + "Builder", Integer.TYPE); } private final Method newBuilderMethod; + private final Method getBuilderMethodBuilder; private Object coerceType(final Object value) { if (type.isInstance(value)) { @@ -2198,6 +2474,12 @@ public abstract class GeneratedMessage extends AbstractMessage public Message.Builder newBuilder() { return (Message.Builder) invokeOrDie(newBuilderMethod, null); } + @Override + public Message.Builder getRepeatedBuilder( + final GeneratedMessage.Builder builder, final int index) { + return (Message.Builder) invokeOrDie( + getBuilderMethodBuilder, builder, index); + } } } @@ -2210,4 +2492,18 @@ public abstract class GeneratedMessage extends AbstractMessage protected Object writeReplace() throws ObjectStreamException { return new GeneratedMessageLite.SerializedForm(this); } + + /** + * Checks that the {@link Extension} is non-Lite and returns it as a + * {@link GeneratedExtension}. + */ + private static , T> + Extension checkNotLite( + ExtensionLite extension) { + if (extension.isLite()) { + throw new IllegalArgumentException("Expected non-lite extension."); + } + + return (Extension) extension; + } } diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 6c5136fd..8fe33bc6 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import com.google.protobuf.WireFormat.FieldType; + import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; @@ -50,10 +52,15 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite implements Serializable { private static final long serialVersionUID = 1L; + /** For use by generated code only. */ + protected UnknownFieldSetLite unknownFields; + protected GeneratedMessageLite() { + unknownFields = UnknownFieldSetLite.getDefaultInstance(); } protected GeneratedMessageLite(Builder builder) { + unknownFields = builder.unknownFields; } public Parser getParserForType() { @@ -62,15 +69,16 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite } /** - * Called by subclasses to parse an unknown field. + * Called by subclasses to parse an unknown field. For use by generated code + * only. * @return {@code true} unless the tag is an end-group tag. */ - protected boolean parseUnknownField( + protected static boolean parseUnknownField( CodedInputStream input, - CodedOutputStream unknownFieldsCodedOutput, + UnknownFieldSetLite.Builder unknownFields, ExtensionRegistryLite extensionRegistry, int tag) throws IOException { - return input.skipField(tag, unknownFieldsCodedOutput); + return unknownFields.mergeFieldFrom(tag, input); } /** @@ -84,22 +92,28 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite public abstract static class Builder extends AbstractMessageLite.Builder { + + private UnknownFieldSetLite unknownFields = + UnknownFieldSetLite.getDefaultInstance(); + protected Builder() {} //@Override (Java 1.6 override semantics, but we must support 1.5) public BuilderType clear() { - unknownFields = ByteString.EMPTY; + unknownFields = UnknownFieldSetLite.getDefaultInstance(); return (BuilderType) this; } - // This is implemented here only to work around an apparent bug in the - // Java compiler and/or build system. See bug #1898463. The mere presence - // of this dummy clone() implementation makes it go away. - @Override + //@Override (Java 1.6 override semantics, but we must support 1.5) public BuilderType clone() { - throw new UnsupportedOperationException( - "This is supposed to be overridden by subclasses."); + BuilderType builder = + (BuilderType) getDefaultInstanceForType().newBuilderForType(); + builder.mergeFrom(buildPartial()); + return builder; } + + /** All subclasses implement this. */ + public abstract MessageType buildPartial(); /** All subclasses implement this. */ public abstract BuilderType mergeFrom(MessageType message); @@ -113,22 +127,43 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite */ protected boolean parseUnknownField( CodedInputStream input, - CodedOutputStream unknownFieldsCodedOutput, + UnknownFieldSetLite.Builder unknownFields, ExtensionRegistryLite extensionRegistry, int tag) throws IOException { - return input.skipField(tag, unknownFieldsCodedOutput); + return unknownFields.mergeFieldFrom(tag, input); } - public final ByteString getUnknownFields() { - return unknownFields; + /** + * Merge some unknown fields into the {@link UnknownFieldSetLite} for this + * message. + * + *

For use by generated code only. + */ + protected final BuilderType mergeUnknownFields( + final UnknownFieldSetLite unknownFields) { + this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields); + return (BuilderType) this; } - - public final BuilderType setUnknownFields(final ByteString unknownFields) { - this.unknownFields = unknownFields; + + public BuilderType mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + MessageType parsedMessage = null; + try { + parsedMessage = + (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom( + input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (MessageType) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } return (BuilderType) this; } - - private ByteString unknownFields = ByteString.EMPTY; } @@ -143,18 +178,18 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite /** Check if a singular extension is present. */ boolean hasExtension( - GeneratedExtension extension); + ExtensionLite extension); /** Get the number of elements in a repeated extension. */ int getExtensionCount( - GeneratedExtension> extension); + ExtensionLite> extension); /** Get the value of an extension. */ - Type getExtension(GeneratedExtension extension); + Type getExtension(ExtensionLite extension); /** Get one element of a repeated extension. */ Type getExtension( - GeneratedExtension> extension, + ExtensionLite> extension, int index); } @@ -166,7 +201,11 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite extends GeneratedMessageLite implements ExtendableMessageOrBuilder { - private final FieldSet extensions; + /** + * Represents the set of extensions on this message. For use by generated + * code only. + */ + protected final FieldSet extensions; protected ExtendableMessage() { this.extensions = FieldSet.newFieldSet(); @@ -190,30 +229,39 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite /** Check if a singular extension is present. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final boolean hasExtension( - final GeneratedExtension extension) { - verifyExtensionContainingType(extension); - return extensions.hasField(extension.descriptor); + final ExtensionLite extension) { + GeneratedExtension extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return extensions.hasField(extensionLite.descriptor); } /** Get the number of elements in a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final int getExtensionCount( - final GeneratedExtension> extension) { - verifyExtensionContainingType(extension); - return extensions.getRepeatedFieldCount(extension.descriptor); + final ExtensionLite> extension) { + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return extensions.getRepeatedFieldCount(extensionLite.descriptor); } /** Get the value of an extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) @SuppressWarnings("unchecked") public final Type getExtension( - final GeneratedExtension extension) { - verifyExtensionContainingType(extension); - final Object value = extensions.getField(extension.descriptor); + final ExtensionLite extension) { + GeneratedExtension extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + final Object value = extensions.getField(extensionLite.descriptor); if (value == null) { - return extension.defaultValue; + return extensionLite.defaultValue; } else { - return (Type) extension.fromFieldSetType(value); + return (Type) extensionLite.fromFieldSetType(value); } } @@ -221,11 +269,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite //@Override (Java 1.6 override semantics, but we must support 1.5) @SuppressWarnings("unchecked") public final Type getExtension( - final GeneratedExtension> extension, + final ExtensionLite> extension, final int index) { - verifyExtensionContainingType(extension); - return (Type) extension.singularFromFieldSetType( - extensions.getRepeatedField(extension.descriptor, index)); + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return (Type) extensionLite.singularFromFieldSetType( + extensions.getRepeatedField(extensionLite.descriptor, index)); } /** Called by subclasses to check if all extensions are initialized. */ @@ -233,25 +284,6 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite return extensions.isInitialized(); } - /** - * Called by subclasses to parse an unknown field or an extension. - * @return {@code true} unless the tag is an end-group tag. - */ - @Override - protected boolean parseUnknownField( - CodedInputStream input, - CodedOutputStream unknownFieldsCodedOutput, - ExtensionRegistryLite extensionRegistry, - int tag) throws IOException { - return GeneratedMessageLite.parseUnknownField( - extensions, - getDefaultInstanceForType(), - input, - unknownFieldsCodedOutput, - extensionRegistry, - tag); - } - /** * Used by parsing constructors in generated classes. @@ -377,30 +409,39 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite /** Check if a singular extension is present. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final boolean hasExtension( - final GeneratedExtension extension) { - verifyExtensionContainingType(extension); - return extensions.hasField(extension.descriptor); + final ExtensionLite extension) { + GeneratedExtension extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return extensions.hasField(extensionLite.descriptor); } /** Get the number of elements in a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final int getExtensionCount( - final GeneratedExtension> extension) { - verifyExtensionContainingType(extension); - return extensions.getRepeatedFieldCount(extension.descriptor); + final ExtensionLite> extension) { + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return extensions.getRepeatedFieldCount(extensionLite.descriptor); } /** Get the value of an extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) @SuppressWarnings("unchecked") public final Type getExtension( - final GeneratedExtension extension) { - verifyExtensionContainingType(extension); - final Object value = extensions.getField(extension.descriptor); + final ExtensionLite extension) { + GeneratedExtension extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + final Object value = extensions.getField(extensionLite.descriptor); if (value == null) { - return extension.defaultValue; + return extensionLite.defaultValue; } else { - return (Type) extension.fromFieldSetType(value); + return (Type) extensionLite.fromFieldSetType(value); } } @@ -408,11 +449,14 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite @SuppressWarnings("unchecked") //@Override (Java 1.6 override semantics, but we must support 1.5) public final Type getExtension( - final GeneratedExtension> extension, + final ExtensionLite> extension, final int index) { - verifyExtensionContainingType(extension); - return (Type) extension.singularFromFieldSetType( - extensions.getRepeatedField(extension.descriptor, index)); + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); + return (Type) extensionLite.singularFromFieldSetType( + extensions.getRepeatedField(extensionLite.descriptor, index)); } // This is implemented here only to work around an apparent bug in the @@ -423,46 +467,57 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite throw new UnsupportedOperationException( "This is supposed to be overridden by subclasses."); } - + /** Set the value of an extension. */ public final BuilderType setExtension( - final GeneratedExtension extension, + final ExtensionLite extension, final Type value) { - verifyExtensionContainingType(extension); + GeneratedExtension extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); ensureExtensionsIsMutable(); - extensions.setField(extension.descriptor, - extension.toFieldSetType(value)); + extensions.setField(extensionLite.descriptor, + extensionLite.toFieldSetType(value)); return (BuilderType) this; } /** Set the value of one element of a repeated extension. */ public final BuilderType setExtension( - final GeneratedExtension> extension, + final ExtensionLite> extension, final int index, final Type value) { - verifyExtensionContainingType(extension); + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); ensureExtensionsIsMutable(); - extensions.setRepeatedField(extension.descriptor, index, - extension.singularToFieldSetType(value)); + extensions.setRepeatedField(extensionLite.descriptor, index, + extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } /** Append a value to a repeated extension. */ public final BuilderType addExtension( - final GeneratedExtension> extension, + final ExtensionLite> extension, final Type value) { - verifyExtensionContainingType(extension); + GeneratedExtension> extensionLite = + checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); ensureExtensionsIsMutable(); - extensions.addRepeatedField(extension.descriptor, - extension.singularToFieldSetType(value)); + extensions.addRepeatedField(extensionLite.descriptor, + extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } /** Clear an extension. */ public final BuilderType clearExtension( - final GeneratedExtension extension) { - verifyExtensionContainingType(extension); + final ExtensionLite extension) { + GeneratedExtension extensionLite = checkIsLite(extension); + + verifyExtensionContainingType(extensionLite); ensureExtensionsIsMutable(); - extensions.clearField(extension.descriptor); + extensions.clearField(extensionLite.descriptor); return (BuilderType) this; } @@ -471,44 +526,24 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite return extensions.isInitialized(); } - /** - * Called by subclasses to parse an unknown field or an extension. - * @return {@code true} unless the tag is an end-group tag. - */ - @Override - protected boolean parseUnknownField( - CodedInputStream input, - CodedOutputStream unknownFieldsCodedOutput, - ExtensionRegistryLite extensionRegistry, - int tag) throws IOException { - ensureExtensionsIsMutable(); - return GeneratedMessageLite.parseUnknownField( - extensions, - getDefaultInstanceForType(), - input, - unknownFieldsCodedOutput, - extensionRegistry, - tag); - } - protected final void mergeExtensionFields(final MessageType other) { ensureExtensionsIsMutable(); extensions.mergeFrom(((ExtendableMessage) other).extensions); } } - // ----------------------------------------------------------------- + //----------------------------------------------------------------- /** - * Parse an unknown field or an extension. + * Parse an unknown field or an extension. For use by generated code only. * @return {@code true} unless the tag is an end-group tag. */ - private static + protected static boolean parseUnknownField( FieldSet extensions, MessageType defaultInstance, CodedInputStream input, - CodedOutputStream unknownFieldsCodedOutput, + UnknownFieldSetLite.Builder unknownFields, ExtensionRegistryLite extensionRegistry, int tag) throws IOException { int wireType = WireFormat.getTagWireType(tag); @@ -537,7 +572,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite } if (unknown) { // Unknown field or wrong wire type. Skip. - return input.skipField(tag, unknownFieldsCodedOutput); + return unknownFields.mergeFieldFrom(tag, input); } if (packed) { @@ -599,8 +634,7 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite // If the number isn't recognized as a valid value for this enum, // write it to unknown fields object. if (value == null) { - unknownFieldsCodedOutput.writeRawVarint32(tag); - unknownFieldsCodedOutput.writeUInt32NoTag(rawValue); + unknownFields.mergeVarintField(fieldNumber, rawValue); return true; } break; @@ -768,7 +802,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite * this type as parameters to extension accessors and ExtensionRegistry.add(). */ public static class GeneratedExtension< - ContainingType extends MessageLite, Type> { + ContainingType extends MessageLite, Type> + extends ExtensionLite { /** * Create a new isntance with the given parameters. @@ -888,6 +923,18 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite return value; } } + + public FieldType getLiteType() { + return descriptor.getLiteType(); + } + + public boolean isRepeated() { + return descriptor.isRepeated; + } + + public Type getDefaultValue() { + return defaultValue; + } } /** @@ -897,8 +944,8 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite static final class SerializedForm implements Serializable { private static final long serialVersionUID = 0L; - private String messageClassName; - private byte[] asBytes; + private final String messageClassName; + private final byte[] asBytes; /** * Creates the serialized form by calling {@link com.google.protobuf.MessageLite#toByteArray}. @@ -918,19 +965,17 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite protected Object readResolve() throws ObjectStreamException { try { Class messageClass = Class.forName(messageClassName); - Method newBuilder = messageClass.getMethod("newBuilder"); - MessageLite.Builder builder = - (MessageLite.Builder) newBuilder.invoke(null); - builder.mergeFrom(asBytes); - return builder.buildPartial(); + Parser parser = + (Parser) messageClass.getField("PARSER").get(null); + return parser.parsePartialFrom(asBytes); } catch (ClassNotFoundException e) { throw new RuntimeException("Unable to find proto buffer class", e); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Unable to find newBuilder method", e); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Unable to find PARSER", e); + } catch (SecurityException e) { + throw new RuntimeException("Unable to call PARSER", e); } catch (IllegalAccessException e) { - throw new RuntimeException("Unable to call newBuilder method", e); - } catch (InvocationTargetException e) { - throw new RuntimeException("Error calling newBuilder", e.getCause()); + throw new RuntimeException("Unable to call parseFrom method", e); } catch (InvalidProtocolBufferException e) { throw new RuntimeException("Unable to understand proto buffer", e); } @@ -946,4 +991,18 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite protected Object writeReplace() throws ObjectStreamException { return new SerializedForm(this); } + + /** + * Checks that the {@link Extension} is Lite and returns it as a + * {@link GeneratedExtension}. + */ + private static , T> + GeneratedExtension checkIsLite( + ExtensionLite extension) { + if (!extension.isLite()) { + throw new IllegalArgumentException("Expected a lite extension."); + } + + return (GeneratedExtension) extension; + } } diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java index 48d29e69..ba0f526b 100644 --- a/java/src/main/java/com/google/protobuf/Internal.java +++ b/java/src/main/java/com/google/protobuf/Internal.java @@ -33,8 +33,14 @@ package com.google.protobuf; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; +import java.util.AbstractList; +import java.util.AbstractMap; +import java.util.AbstractSet; import java.util.Arrays; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Set; /** * The classes contained within are used internally by the Protocol Buffer @@ -388,4 +394,164 @@ public class Internal { public static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.wrap(EMPTY_BYTE_ARRAY); + + /** + * Provides an immutable view of List around a List. + * + * Protobuf internal. Used in protobuf generated code only. + */ + public static class ListAdapter extends AbstractList { + /** + * Convert individual elements of the List from F to T. + */ + public interface Converter { + T convert(F from); + } + + private final List fromList; + private final Converter converter; + + public ListAdapter(List fromList, Converter converter) { + this.fromList = fromList; + this.converter = converter; + } + + @Override + public T get(int index) { + return converter.convert(fromList.get(index)); + } + + @Override + public int size() { + return fromList.size(); + } + } + + /** + * Wrap around a Map and provide a Map interface. + */ + public static class MapAdapter extends AbstractMap { + /** + * An interface used to convert between two types. + */ + public interface Converter { + B doForward(A object); + A doBackward(B object); + } + + public static Converter newEnumConverter( + final EnumLiteMap enumMap, final T unrecognizedValue) { + return new Converter() { + public T doForward(Integer value) { + T result = enumMap.findValueByNumber(value); + return result == null ? unrecognizedValue : result; + } + public Integer doBackward(T value) { + return value.getNumber(); + } + }; + } + + private final Map realMap; + private final Converter valueConverter; + + public MapAdapter(Map realMap, + Converter valueConverter) { + this.realMap = realMap; + this.valueConverter = valueConverter; + } + + @SuppressWarnings("unchecked") + @Override + public V get(Object key) { + RealValue result = realMap.get(key); + if (result == null) { + return null; + } + return valueConverter.doForward(result); + } + + @Override + public V put(K key, V value) { + RealValue oldValue = realMap.put(key, valueConverter.doBackward(value)); + if (oldValue == null) { + return null; + } + return valueConverter.doForward(oldValue); + } + + @Override + public Set> entrySet() { + return new SetAdapter(realMap.entrySet()); + } + + private class SetAdapter extends AbstractSet> { + private final Set> realSet; + public SetAdapter(Set> realSet) { + this.realSet = realSet; + } + + @Override + public Iterator> iterator() { + return new IteratorAdapter(realSet.iterator()); + } + + @Override + public int size() { + return realSet.size(); + } + } + + private class IteratorAdapter implements Iterator> { + private final Iterator> realIterator; + + public IteratorAdapter( + Iterator> realIterator) { + this.realIterator = realIterator; + } + + @Override + public boolean hasNext() { + return realIterator.hasNext(); + } + + @Override + public java.util.Map.Entry next() { + return new EntryAdapter(realIterator.next()); + } + + @Override + public void remove() { + realIterator.remove(); + } + } + + private class EntryAdapter implements Map.Entry { + private final Map.Entry realEntry; + + public EntryAdapter(Map.Entry realEntry) { + this.realEntry = realEntry; + } + + @Override + public K getKey() { + return realEntry.getKey(); + } + + @Override + public V getValue() { + return valueConverter.doForward(realEntry.getValue()); + } + + @Override + public V setValue(V value) { + RealValue oldValue = realEntry.setValue( + valueConverter.doBackward(value)); + if (oldValue == null) { + return null; + } + return valueConverter.doForward(oldValue); + } + } + } } diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java index 61c7e1ea..2d40a51f 100644 --- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -74,6 +74,10 @@ public class LazyStringArrayList extends AbstractList list = new ArrayList(); } + public LazyStringArrayList(int intialCapacity) { + list = new ArrayList(intialCapacity); + } + public LazyStringArrayList(LazyStringList from) { list = new ArrayList(from.size()); addAll(from); diff --git a/java/src/main/java/com/google/protobuf/LiteralByteString.java b/java/src/main/java/com/google/protobuf/LiteralByteString.java index 83e71e93..127c574d 100644 --- a/java/src/main/java/com/google/protobuf/LiteralByteString.java +++ b/java/src/main/java/com/google/protobuf/LiteralByteString.java @@ -190,6 +190,15 @@ class LiteralByteString extends ByteString { } if (other instanceof LiteralByteString) { + LiteralByteString otherAsLiteral = (LiteralByteString) other; + // If we know the hash codes and they are not equal, we know the byte + // strings are not equal. + if (hash != 0 + && otherAsLiteral.hash != 0 + && hash != otherAsLiteral.hash) { + return false; + } + return equalsRange((LiteralByteString) other, 0, size()); } else if (other instanceof RopeByteString) { return other.equals(this); diff --git a/java/src/main/java/com/google/protobuf/MapEntry.java b/java/src/main/java/com/google/protobuf/MapEntry.java new file mode 100644 index 00000000..8e3551b6 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MapEntry.java @@ -0,0 +1,433 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +/** + * Implements MapEntry messages. + * + * In reflection API, map fields will be treated as repeated message fields and + * each map entry is accessed as a message. This MapEntry class is used to + * represent these map entry messages in reflection API. + * + * Protobuf internal. Users shouldn't use this class. + */ +public final class MapEntry extends AbstractMessage { + private static class Metadata { + public final Descriptor descriptor; + public final MapEntry defaultInstance; + public final AbstractParser> parser; + + public Metadata( + final Descriptor descriptor, final MapEntry defaultInstance) { + this.descriptor = descriptor; + this.defaultInstance = defaultInstance; + final Metadata thisMetadata = this; + this.parser = new AbstractParser>() { + private final Parser> dataParser = + defaultInstance.data.getParserForType(); + @Override + public MapEntry parsePartialFrom( + CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + MapEntryLite data = + dataParser.parsePartialFrom(input, extensionRegistry); + return new MapEntry(thisMetadata, data); + } + + }; + } + } + + private final Metadata metadata; + private final MapEntryLite data; + + /** Create a default MapEntry instance. */ + private MapEntry(Descriptor descriptor, + WireFormat.FieldType keyType, K defaultKey, + WireFormat.FieldType valueType, V defaultValue) { + this.data = MapEntryLite.newDefaultInstance( + keyType, defaultKey, valueType, defaultValue); + this.metadata = new Metadata(descriptor, this); + } + + /** Create a new MapEntry message. */ + private MapEntry(Metadata metadata, MapEntryLite data) { + this.metadata = metadata; + this.data = data; + } + + /** + * Create a default MapEntry instance. A default MapEntry instance should be + * created only once for each map entry message type. Generated code should + * store the created default instance and use it later to create new MapEntry + * messages of the same type. + */ + public static MapEntry newDefaultInstance( + Descriptor descriptor, + WireFormat.FieldType keyType, K defaultKey, + WireFormat.FieldType valueType, V defaultValue) { + return new MapEntry( + descriptor, keyType, defaultKey, valueType, defaultValue); + } + + public K getKey() { + return data.getKey(); + } + + public V getValue() { + return data.getValue(); + } + + @Override + public int getSerializedSize() { + return data.getSerializedSize(); + } + + @Override + public void writeTo(CodedOutputStream output) throws IOException { + data.writeTo(output); + } + + @Override + public boolean isInitialized() { + return data.isInitialized(); + } + + @Override + public Parser> getParserForType() { + return metadata.parser; + } + + @Override + public Builder newBuilderForType() { + return new Builder(metadata); + } + + @Override + public Builder toBuilder() { + return new Builder(metadata, data); + } + + @Override + public MapEntry getDefaultInstanceForType() { + return metadata.defaultInstance; + } + + @Override + public Descriptor getDescriptorForType() { + return metadata.descriptor; + } + + @Override + public Map getAllFields() { + final TreeMap result = + new TreeMap(); + for (final FieldDescriptor field : metadata.descriptor.getFields()) { + if (hasField(field)) { + result.put(field, getField(field)); + } + } + return Collections.unmodifiableMap(result); + } + + private void checkFieldDescriptor(FieldDescriptor field) { + if (field.getContainingType() != metadata.descriptor) { + throw new RuntimeException( + "Wrong FieldDescriptor \"" + field.getFullName() + + "\" used in message \"" + metadata.descriptor.getFullName()); + } + } + + @Override + public boolean hasField(FieldDescriptor field) { + checkFieldDescriptor(field);; + // A MapEntry always contains two fields. + return true; + } + + @Override + public Object getField(FieldDescriptor field) { + checkFieldDescriptor(field); + Object result = field.getNumber() == 1 ? getKey() : getValue(); + // Convert enums to EnumValueDescriptor. + if (field.getType() == FieldDescriptor.Type.ENUM) { + result = field.getEnumType().findValueByNumberCreatingIfUnknown( + (java.lang.Integer) result); + } + return result; + } + + @Override + public int getRepeatedFieldCount(FieldDescriptor field) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public Object getRepeatedField(FieldDescriptor field, int index) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public UnknownFieldSet getUnknownFields() { + return UnknownFieldSet.getDefaultInstance(); + } + + /** + * Builder to create {@link MapEntry} messages. + */ + public static class Builder + extends AbstractMessage.Builder> { + private final Metadata metadata; + private MapEntryLite data; + private MapEntryLite.Builder dataBuilder; + + private Builder(Metadata metadata) { + this.metadata = metadata; + this.data = metadata.defaultInstance.data; + this.dataBuilder = null; + } + + private Builder(Metadata metadata, MapEntryLite data) { + this.metadata = metadata; + this.data = data; + this.dataBuilder = null; + } + + public K getKey() { + return dataBuilder == null ? data.getKey() : dataBuilder.getKey(); + } + + public V getValue() { + return dataBuilder == null ? data.getValue() : dataBuilder.getValue(); + } + + private void ensureMutable() { + if (dataBuilder == null) { + dataBuilder = data.toBuilder(); + } + } + + public Builder setKey(K key) { + ensureMutable(); + dataBuilder.setKey(key); + return this; + } + + public Builder clearKey() { + ensureMutable(); + dataBuilder.clearKey(); + return this; + } + + public Builder setValue(V value) { + ensureMutable(); + dataBuilder.setValue(value); + return this; + } + + public Builder clearValue() { + ensureMutable(); + dataBuilder.clearValue(); + return this; + } + + @Override + public MapEntry build() { + MapEntry result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public MapEntry buildPartial() { + if (dataBuilder != null) { + data = dataBuilder.build(); + dataBuilder = null; + } + return new MapEntry(metadata, data); + } + + @Override + public Descriptor getDescriptorForType() { + return metadata.descriptor; + } + + private void checkFieldDescriptor(FieldDescriptor field) { + if (field.getContainingType() != metadata.descriptor) { + throw new RuntimeException( + "Wrong FieldDescriptor \"" + field.getFullName() + + "\" used in message \"" + metadata.descriptor.getFullName()); + } + } + + @Override + public com.google.protobuf.Message.Builder newBuilderForField( + FieldDescriptor field) { + checkFieldDescriptor(field);; + // This method should be called for message fields and in a MapEntry + // message only the value field can possibly be a message field. + if (field.getNumber() != 2 + || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { + throw new RuntimeException( + "\"" + field.getFullName() + "\" is not a message value field."); + } + return ((Message) data.getValue()).newBuilderForType(); + } + + @SuppressWarnings("unchecked") + @Override + public Builder setField(FieldDescriptor field, Object value) { + checkFieldDescriptor(field); + if (field.getNumber() == 1) { + setKey((K) value); + } else { + if (field.getType() == FieldDescriptor.Type.ENUM) { + value = ((EnumValueDescriptor) value).getNumber(); + } + setValue((V) value); + } + return this; + } + + @Override + public Builder clearField(FieldDescriptor field) { + checkFieldDescriptor(field); + if (field.getNumber() == 1) { + clearKey(); + } else { + clearValue(); + } + return this; + } + + @Override + public Builder setRepeatedField(FieldDescriptor field, int index, + Object value) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public Builder addRepeatedField(FieldDescriptor field, Object value) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public Builder setUnknownFields(UnknownFieldSet unknownFields) { + // Unknown fields are discarded for MapEntry message. + return this; + } + + @Override + public MapEntry getDefaultInstanceForType() { + return metadata.defaultInstance; + } + + @Override + public boolean isInitialized() { + if (dataBuilder != null) { + return dataBuilder.isInitialized(); + } else { + return data.isInitialized(); + } + } + + @Override + public Map getAllFields() { + final TreeMap result = + new TreeMap(); + for (final FieldDescriptor field : metadata.descriptor.getFields()) { + if (hasField(field)) { + result.put(field, getField(field)); + } + } + return Collections.unmodifiableMap(result); + } + + @Override + public boolean hasField(FieldDescriptor field) { + checkFieldDescriptor(field); + return true; + } + + @Override + public Object getField(FieldDescriptor field) { + checkFieldDescriptor(field); + Object result = field.getNumber() == 1 ? getKey() : getValue(); + // Convert enums to EnumValueDescriptor. + if (field.getType() == FieldDescriptor.Type.ENUM) { + result = field.getEnumType().findValueByNumberCreatingIfUnknown( + (java.lang.Integer) result); + } + return result; + } + + @Override + public int getRepeatedFieldCount(FieldDescriptor field) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public Object getRepeatedField(FieldDescriptor field, int index) { + throw new RuntimeException( + "There is no repeated field in a map entry message."); + } + + @Override + public UnknownFieldSet getUnknownFields() { + return UnknownFieldSet.getDefaultInstance(); + } + + @Override + public Builder clone() { + if (dataBuilder == null) { + return new Builder(metadata, data); + } else { + return new Builder(metadata, dataBuilder.build()); + } + } + } +} diff --git a/java/src/main/java/com/google/protobuf/MapEntryLite.java b/java/src/main/java/com/google/protobuf/MapEntryLite.java new file mode 100644 index 00000000..bcffa946 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MapEntryLite.java @@ -0,0 +1,331 @@ +// 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. + +package com.google.protobuf; + +import java.io.IOException; + +/** + * Implements the lite version of map entry messages. + * + * This class serves as an utility class to help do serialization/parsing of + * map entries. It's used in generated code and also in the full version + * MapEntry message. + * + * Protobuf internal. Users shouldn't use. + */ +public class MapEntryLite extends AbstractMessageLite { + private static class Metadata { + public final MapEntryLite defaultInstance; + public final WireFormat.FieldType keyType; + public final WireFormat.FieldType valueType; + public final Parser> parser; + public Metadata( + MapEntryLite defaultInstance, + WireFormat.FieldType keyType, + WireFormat.FieldType valueType) { + this.defaultInstance = defaultInstance; + this.keyType = keyType; + this.valueType = valueType; + final Metadata finalThis = this; + this.parser = new AbstractParser>() { + @Override + public MapEntryLite parsePartialFrom( + CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return new MapEntryLite(finalThis, input, extensionRegistry); + } + }; + } + } + + private static final int KEY_FIELD_NUMBER = 1; + private static final int VALUE_FIELD_NUMBER = 2; + + private final Metadata metadata; + private final K key; + private final V value; + + /** Creates a default MapEntryLite message instance. */ + private MapEntryLite( + WireFormat.FieldType keyType, K defaultKey, + WireFormat.FieldType valueType, V defaultValue) { + this.metadata = new Metadata(this, keyType, valueType); + this.key = defaultKey; + this.value = defaultValue; + } + + /** Creates a new MapEntryLite message. */ + private MapEntryLite(Metadata metadata, K key, V value) { + this.metadata = metadata; + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + /** + * Creates a default MapEntryLite message instance. + * + * This method is used by generated code to create the default instance for + * a map entry message. The created default instance should be used to create + * new map entry messages of the same type. For each map entry message, only + * one default instance should be created. + */ + public static MapEntryLite newDefaultInstance( + WireFormat.FieldType keyType, K defaultKey, + WireFormat.FieldType valueType, V defaultValue) { + return new MapEntryLite( + keyType, defaultKey, valueType, defaultValue); + } + + @Override + public void writeTo(CodedOutputStream output) throws IOException { + writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output); + writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output); + } + + private void writeField( + int number, WireFormat.FieldType type, Object value, + CodedOutputStream output) throws IOException { + output.writeTag(number, type.getWireType()); + FieldSet.writeElementNoTag(output, type, value); + } + + private volatile int cachedSerializedSize = -1; + @Override + public int getSerializedSize() { + if (cachedSerializedSize != -1) { + return cachedSerializedSize; + } + int size = 0; + size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key); + size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value); + cachedSerializedSize = size; + return size; + } + + private int getFieldSize( + int number, WireFormat.FieldType type, Object value) { + return CodedOutputStream.computeTagSize(number) + + FieldSet.computeElementSizeNoTag(type, value); + } + + /** Parsing constructor. */ + private MapEntryLite( + Metadata metadata, + CodedInputStream input, + ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + K key = metadata.defaultInstance.key; + V value = metadata.defaultInstance.value; + while (true) { + int tag = input.readTag(); + if (tag == 0) { + break; + } + if (tag == WireFormat.makeTag( + KEY_FIELD_NUMBER, metadata.keyType.getWireType())) { + key = mergeField( + input, extensionRegistry, metadata.keyType, key); + } else if (tag == WireFormat.makeTag( + VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) { + value = mergeField( + input, extensionRegistry, metadata.valueType, value); + } else { + if (!input.skipField(tag)) { + break; + } + } + } + this.metadata = metadata; + this.key = key; + this.value = value; + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (IOException e) { + throw new InvalidProtocolBufferException(e.getMessage()) + .setUnfinishedMessage(this); + } + } + + @SuppressWarnings("unchecked") + private T mergeField( + CodedInputStream input, ExtensionRegistryLite extensionRegistry, + WireFormat.FieldType type, T value) throws IOException { + switch (type) { + case MESSAGE: + MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); + input.readMessage(subBuilder, extensionRegistry); + return (T) subBuilder.buildPartial(); + case ENUM: + return (T) (java.lang.Integer) input.readEnum(); + case GROUP: + throw new RuntimeException("Groups are not allowed in maps."); + default: + return (T) FieldSet.readPrimitiveField(input, type, true); + } + } + + @Override + public Parser> getParserForType() { + return metadata.parser; + } + + @Override + public Builder newBuilderForType() { + return new Builder(metadata); + } + + @Override + public Builder toBuilder() { + return new Builder(metadata, key, value); + } + + @Override + public MapEntryLite getDefaultInstanceForType() { + return metadata.defaultInstance; + } + + @Override + public boolean isInitialized() { + if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { + return ((MessageLite) value).isInitialized(); + } + return true; + } + + /** + * Builder used to create {@link MapEntryLite} messages. + */ + public static class Builder + extends AbstractMessageLite.Builder> { + private final Metadata metadata; + private K key; + private V value; + + private Builder(Metadata metadata) { + this.metadata = metadata; + this.key = metadata.defaultInstance.key; + this.value = metadata.defaultInstance.value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public Builder setKey(K key) { + this.key = key; + return this; + } + + public Builder setValue(V value) { + this.value = value; + return this; + } + + public Builder clearKey() { + this.key = metadata.defaultInstance.key; + return this; + } + + public Builder clearValue() { + this.value = metadata.defaultInstance.value; + return this; + } + + @Override + public Builder clear() { + this.key = metadata.defaultInstance.key; + this.value = metadata.defaultInstance.value; + return this; + } + + @Override + public MapEntryLite build() { + MapEntryLite result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public MapEntryLite buildPartial() { + return new MapEntryLite(metadata, key, value); + } + + @Override + public MessageLite getDefaultInstanceForType() { + return metadata.defaultInstance; + } + + @Override + public boolean isInitialized() { + if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { + return ((MessageLite) value).isInitialized(); + } + return true; + } + + private Builder(Metadata metadata, K key, V value) { + this.metadata = metadata; + this.key = key; + this.value = value; + } + + @Override + public Builder clone() { + return new Builder(metadata, key, value); + } + + @Override + public Builder mergeFrom( + CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { + MapEntryLite entry = + new MapEntryLite(metadata, input, extensionRegistry); + this.key = entry.key; + this.value = entry.value; + return this; + } + } +} diff --git a/java/src/main/java/com/google/protobuf/MapField.java b/java/src/main/java/com/google/protobuf/MapField.java new file mode 100644 index 00000000..5bd70dbb --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MapField.java @@ -0,0 +1,259 @@ +// 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. + +package com.google.protobuf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Internal representation of map fields in generated messages. + * + * This class supports accessing the map field as a {@link Map} to be used in + * generated API and also supports accessing the field as a {@link List} to be + * used in reflection API. It keeps track of where the data is currently stored + * and do necessary conversions between map and list. + * + * This class is a protobuf implementation detail. Users shouldn't use this + * class directly. + * + * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() + * and getList() concurrently in multiple threads. If write-access is needed, + * all access must be synchronized. + */ +public class MapField { + /** + * Indicates where the data of this map field is currently stored. + * + * MAP: Data is stored in mapData. + * LIST: Data is stored in listData. + * BOTH: mapData and listData have the same data. + * + * When the map field is accessed (through generated API or reflection API), + * it will shift between these 3 modes: + * + * getMap() getList() getMutableMap() getMutableList() + * MAP MAP BOTH MAP LIST + * LIST BOTH LIST MAP LIST + * BOTH BOTH BOTH MAP LIST + * + * As the map field changes its mode, the list/map reference returned in a + * previous method call may be invalidated. + */ + private enum StorageMode {MAP, LIST, BOTH} + + private volatile StorageMode mode; + private Map mapData; + private List listData; + + // Convert between a map entry Message and a key-value pair. + private static interface Converter { + Message convertKeyAndValueToMessage(K key, V value); + void convertMessageToKeyAndValue(Message message, Map map); + + Message getMessageDefaultInstance(); + } + + private static class ImmutableMessageConverter implements Converter { + private final MapEntry defaultEntry; + public ImmutableMessageConverter(MapEntry defaultEntry) { + this.defaultEntry = defaultEntry; + } + + public Message convertKeyAndValueToMessage(K key, V value) { + return defaultEntry.newBuilderForType().setKey(key).setValue(value).build(); + } + + public void convertMessageToKeyAndValue(Message message, Map map) { + MapEntry entry = (MapEntry) message; + map.put(entry.getKey(), entry.getValue()); + } + + public Message getMessageDefaultInstance() { + return defaultEntry; + } + } + + + private final Converter converter; + + private MapField( + Converter converter, + StorageMode mode, + Map mapData, + List listData) { + this.converter = converter; + this.mode = mode; + this.mapData = mapData; + this.listData = listData; + } + + private MapField( + MapEntry defaultEntry, + StorageMode mode, + Map mapData, + List listData) { + this(new ImmutableMessageConverter(defaultEntry), mode, mapData, listData); + } + + + /** Returns an immutable empty MapField. */ + public static MapField emptyMapField( + MapEntry defaultEntry) { + return new MapField( + defaultEntry, StorageMode.MAP, Collections.emptyMap(), null); + } + + + /** Creates a new mutable empty MapField. */ + public static MapField newMapField(MapEntry defaultEntry) { + return new MapField( + defaultEntry, StorageMode.MAP, new HashMap(), null); + } + + + private Message convertKeyAndValueToMessage(K key, V value) { + return converter.convertKeyAndValueToMessage(key, value); + } + + @SuppressWarnings("unchecked") + private void convertMessageToKeyAndValue(Message message, Map map) { + converter.convertMessageToKeyAndValue(message, map); + } + + private List convertMapToList(Map mapData) { + List listData = new ArrayList(); + for (Map.Entry entry : mapData.entrySet()) { + listData.add( + convertKeyAndValueToMessage( + entry.getKey(), entry.getValue())); + } + return listData; + } + + private Map convertListToMap(List listData) { + Map mapData = new HashMap(); + for (Message item : listData) { + convertMessageToKeyAndValue(item, mapData); + } + return mapData; + } + + /** Returns the content of this MapField as a read-only Map. */ + public Map getMap() { + if (mode == StorageMode.LIST) { + synchronized (this) { + if (mode == StorageMode.LIST) { + mapData = convertListToMap(listData); + mode = StorageMode.BOTH; + } + } + } + return Collections.unmodifiableMap(mapData); + } + + /** Gets a mutable Map view of this MapField. */ + public Map getMutableMap() { + if (mode != StorageMode.MAP) { + if (mode == StorageMode.LIST) { + mapData = convertListToMap(listData); + } + listData = null; + mode = StorageMode.MAP; + } + return mapData; + } + + public void mergeFrom(MapField other) { + getMutableMap().putAll(MapFieldLite.copy(other.getMap())); + } + + public void clear() { + mapData = new HashMap(); + mode = StorageMode.MAP; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object object) { + if (!(object instanceof MapField)) { + return false; + } + MapField other = (MapField) object; + return MapFieldLite.equals(getMap(), other.getMap()); + } + + @Override + public int hashCode() { + return MapFieldLite.calculateHashCodeForMap(getMap()); + } + + /** Returns a deep copy of this MapField. */ + public MapField copy() { + return new MapField( + converter, StorageMode.MAP, MapFieldLite.copy(getMap()), null); + } + + /** Gets the content of this MapField as a read-only List. */ + List getList() { + if (mode == StorageMode.MAP) { + synchronized (this) { + if (mode == StorageMode.MAP) { + listData = convertMapToList(mapData); + mode = StorageMode.BOTH; + } + } + } + return Collections.unmodifiableList(listData); + } + + /** Gets a mutable List view of this MapField. */ + List getMutableList() { + if (mode != StorageMode.LIST) { + if (mode == StorageMode.MAP) { + listData = convertMapToList(mapData); + } + mapData = null; + mode = StorageMode.LIST; + } + return listData; + } + + /** + * Gets the default instance of the message stored in the list view of this + * map field. + */ + Message getMapEntryMessageDefaultInstance() { + return converter.getMessageDefaultInstance(); + } +} diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/src/main/java/com/google/protobuf/MapFieldLite.java new file mode 100644 index 00000000..eea36d9e --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MapFieldLite.java @@ -0,0 +1,182 @@ +// 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. + +package com.google.protobuf; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Internal representation of map fields in generated lite-runtime messages. + * + * This class is a protobuf implementation detail. Users shouldn't use this + * class directly. + */ +public class MapFieldLite { + private Map mapData; + + private MapFieldLite(Map mapData) { + this.mapData = mapData; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static final MapFieldLite EMPTY_MAP_FIELD = + new MapFieldLite(Collections.emptyMap()); + + /** Returns an singleton immutable empty MapFieldLite instance. */ + @SuppressWarnings({"unchecked", "cast"}) + public static MapFieldLite emptyMapField() { + return (MapFieldLite) EMPTY_MAP_FIELD; + } + + /** Creates a new MapFieldLite instance. */ + public static MapFieldLite newMapField() { + return new MapFieldLite(new HashMap()); + } + + /** Gets the content of this MapField as a read-only Map. */ + public Map getMap() { + return Collections.unmodifiableMap(mapData); + } + + /** Gets a mutable Map view of this MapField. */ + public Map getMutableMap() { + return mapData; + } + + public void mergeFrom(MapFieldLite other) { + mapData.putAll(copy(other.mapData)); + } + + public void clear() { + mapData.clear(); + } + + private static boolean equals(Object a, Object b) { + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + return a.equals(b); + } + + /** + * Checks whether two {@link Map}s are equal. We don't use the default equals + * method of {@link Map} because it compares by identity not by content for + * byte arrays. + */ + static boolean equals(Map a, Map b) { + if (a == b) { + return true; + } + if (a.size() != a.size()) { + return false; + } + for (Map.Entry entry : a.entrySet()) { + if (!b.containsKey(entry.getKey())) { + return false; + } + if (!equals(entry.getValue(), b.get(entry.getKey()))) { + return false; + } + } + return true; + } + + /** + * Checks whether two map fields are equal. + */ + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object object) { + if (!(object instanceof MapFieldLite)) { + return false; + } + MapFieldLite other = (MapFieldLite) object; + return equals(mapData, other.mapData); + } + + private static int calculateHashCodeForObject(Object a) { + if (a instanceof byte[]) { + return LiteralByteString.hashCode((byte[]) a); + } + if (a instanceof Internal.EnumLite) { + return Internal.hashEnum((Internal.EnumLite) a); + } + return a.hashCode(); + } + + /** + * Calculates the hash code for a {@link Map}. We don't use the default hash + * code method of {@link Map} because for byte arrays and protobuf enums it + * use {@link Object#hashCode()}. + */ + static int calculateHashCodeForMap(Map a) { + int result = 0; + for (Map.Entry entry : a.entrySet()) { + result += calculateHashCodeForObject(entry.getKey()) + ^ calculateHashCodeForObject(entry.getValue()); + } + return result; + } + + @Override + public int hashCode() { + return calculateHashCodeForMap(mapData); + } + + private static Object copy(Object object) { + if (object instanceof byte[]) { + byte[] data = (byte[]) object; + return Arrays.copyOf(data, data.length); + } + return object; + } + + /** + * Makes a deep copy of a {@link Map}. Immutable objects in the map will be + * shared (e.g., integers, strings, immutable messages) and mutable ones will + * have a copy (e.g., byte arrays, mutable messages). + */ + @SuppressWarnings("unchecked") + static Map copy(Map map) { + Map result = new HashMap(); + for (Map.Entry entry : map.entrySet()) { + result.put(entry.getKey(), (V) copy(entry.getValue())); + } + return result; + } + + /** Returns a deep copy of this map field. */ + public MapFieldLite copy() { + return new MapFieldLite(copy(mapData)); + } +} diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java index 5673d3bb..5c75b58b 100644 --- a/java/src/main/java/com/google/protobuf/Message.java +++ b/java/src/main/java/com/google/protobuf/Message.java @@ -167,6 +167,25 @@ public interface Message extends MessageLite, MessageOrBuilder { */ Builder getFieldBuilder(Descriptors.FieldDescriptor field); + /** + * Get a nested builder instance for the given repeated field instance. + *

+ * Normally, we hold a reference to the immutable message object for the + * message type field. Some implementations(the generated message builders), + * however, can also hold a reference to the builder object (a nested + * builder) for the field. + *

+ * If the field is already backed up by a nested builder, the nested builder + * will be returned. Otherwise, a new field builder will be created and + * returned. The original message field (if exist) will be merged into the + * field builder, which will then be nested into its parent builder. + *

+ * NOTE: implementations that do not support nested builders will throw + * UnsupportedException. + */ + Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field, + int index); + /** * Sets a field to the given value. The value must be of the correct type * for this field, i.e. the same type that diff --git a/java/src/main/java/com/google/protobuf/MessageReflection.java b/java/src/main/java/com/google/protobuf/MessageReflection.java index edb5b5c2..06e3c99b 100644 --- a/java/src/main/java/com/google/protobuf/MessageReflection.java +++ b/java/src/main/java/com/google/protobuf/MessageReflection.java @@ -752,13 +752,18 @@ class MessageReflection { if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); - final Object value = field.getEnumType().findValueByNumber(rawValue); - if (value == null) { - // If the number isn't recognized as a valid value for this - // enum, drop it (don't even add it to unknownFields). - return true; + if (field.getFile().supportsUnknownEnumValue()) { + target.addRepeatedField(field, + field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue)); + } else { + final Object value = field.getEnumType().findValueByNumber(rawValue); + if (value == null) { + // If the number isn't recognized as a valid value for this + // enum, drop it (don't even add it to unknownFields). + return true; + } + target.addRepeatedField(field, value); } - target.addRepeatedField(field, value); } } else { while (input.getBytesUntilLimit() > 0) { @@ -783,12 +788,16 @@ class MessageReflection { } case ENUM: final int rawValue = input.readEnum(); - value = field.getEnumType().findValueByNumber(rawValue); - // If the number isn't recognized as a valid value for this enum, - // drop it. - if (value == null) { - unknownFields.mergeVarintField(fieldNumber, rawValue); - return true; + if (field.getFile().supportsUnknownEnumValue()) { + value = field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue); + } else { + value = field.getEnumType().findValueByNumber(rawValue); + // If the number isn't recognized as a valid value for this enum, + // drop it. + if (value == null) { + unknownFields.mergeVarintField(fieldNumber, rawValue); + return true; + } } break; default: diff --git a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java index 22760d3a..63535ac8 100644 --- a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java +++ b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java @@ -367,22 +367,28 @@ public class RepeatedFieldBuilder throw new NullPointerException(); } } + + // If we can inspect the size, we can more efficiently add messages. + int size = -1; if (values instanceof Collection) { @SuppressWarnings("unchecked") final Collection collection = (Collection) values; if (collection.size() == 0) { return this; } - ensureMutableMessageList(); - for (MType value : values) { - addMessage(value); - } - } else { - ensureMutableMessageList(); - for (MType value : values) { - addMessage(value); - } + size = collection.size(); + } + ensureMutableMessageList(); + + if (size >= 0 && messages instanceof ArrayList) { + ((ArrayList) messages) + .ensureCapacity(messages.size() + size); } + + for (MType value : values) { + addMessage(value); + } + onChanged(); incrementModCounts(); return this; diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index 57d0ca68..44674811 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -1211,6 +1211,7 @@ public final class TextFormat { private SingularOverwritePolicy singularOverwritePolicy = SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES; + /** * Sets parser behavior when a non-repeated field appears more than once. */ @@ -1418,6 +1419,12 @@ public final class TextFormat { } else { consumeFieldValue(tokenizer, extensionRegistry, target, field, extension); } + + // For historical reasons, fields may optionally be separated by commas or + // semicolons. + if (!tokenizer.tryConsume(";")) { + tokenizer.tryConsume(","); + } } /** @@ -1656,10 +1663,9 @@ public final class TextFormat { case '\'': builder.append("\\\'"); break; case '"' : builder.append("\\\""); break; default: - // Note: Bytes with the high-order bit set should be escaped. Since - // bytes are signed, such bytes will compare less than 0x20, hence - // the following line is correct. - if (b >= 0x20) { + // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are + // printable. Other byte values must be escaped. + if (b >= 0x20 && b <= 0x7e) { builder.append((char) b); } else { builder.append('\\'); diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java index 99de3732..7cd2250e 100644 --- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -431,6 +431,21 @@ public final class UnknownFieldSet implements MessageLite { return this; } + + /** + * Convenience method for merging a length-delimited field. + * + *

For use by generated code only. + */ + public Builder mergeLengthDelimitedField( + final int number, final ByteString value) { + if (number == 0) { + throw new IllegalArgumentException("Zero is not a valid field number."); + } + getFieldBuilder(number).addLengthDelimited(value); + return this; + } + /** Check if the given field number is present in the set. */ public boolean hasField(final int number) { if (number == 0) { diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java new file mode 100644 index 00000000..7ea84022 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java @@ -0,0 +1,297 @@ +// 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. + +package com.google.protobuf; + +import java.io.IOException; + +/** + * {@code UnknownFieldSetLite} is used to keep track of fields which were seen + * when parsing a protocol message but whose field numbers or types are + * unrecognized. This most frequently occurs when new fields are added to a + * message type and then messages containing those fields are read by old + * software that was compiled before the new types were added. + * + *

For use by generated code only. + * + * @author dweis@google.com (Daniel Weis) + */ +public final class UnknownFieldSetLite { + + private static final UnknownFieldSetLite DEFAULT_INSTANCE = + new UnknownFieldSetLite(ByteString.EMPTY); + + /** + * Get an empty {@code UnknownFieldSetLite}. + * + *

For use by generated code only. + */ + public static UnknownFieldSetLite getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + /** + * Create a new {@link Builder}. + * + *

For use by generated code only. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and + * {@code second}. + */ + static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) { + return new UnknownFieldSetLite(first.byteString.concat(second.byteString)); + } + + /** + * The internal representation of the unknown fields. + */ + private final ByteString byteString; + + /** + * Constructs the {@code UnknownFieldSetLite} as a thin wrapper around {@link ByteString}. + */ + private UnknownFieldSetLite(ByteString byteString) { + this.byteString = byteString; + } + + /** + * Serializes the set and writes it to {@code output}. + * + *

For use by generated code only. + */ + public void writeTo(CodedOutputStream output) throws IOException { + output.writeRawBytes(byteString); + } + + + /** + * Get the number of bytes required to encode this set. + * + *

For use by generated code only. + */ + public int getSerializedSize() { + return byteString.size(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj instanceof UnknownFieldSetLite) { + return byteString.equals(((UnknownFieldSetLite) obj).byteString); + } + + return false; + } + + @Override + public int hashCode() { + return byteString.hashCode(); + } + + /** + * Builder for {@link UnknownFieldSetLite}s. + * + *

Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}. + * + *

For use by generated code only. + */ + public static final class Builder { + + private ByteString.Output byteStringOutput; + private CodedOutputStream output; + private boolean built; + + /** + * Constructs a {@code Builder}. Lazily initialized by + * {@link #ensureInitializedButNotBuilt()}. + */ + private Builder() {} + + /** + * Ensures internal state is initialized for use. + */ + private void ensureInitializedButNotBuilt() { + if (built) { + throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); + } + + if (output == null && byteStringOutput == null) { + byteStringOutput = ByteString.newOutput(100 /* initialCapacity */); + output = CodedOutputStream.newInstance(byteStringOutput); + } + } + + /** + * Parse a single field from {@code input} and merge it into this set. + * + *

For use by generated code only. + * + * @param tag The field's tag number, which was already parsed. + * @return {@code false} if the tag is an end group tag. + */ + public boolean mergeFieldFrom(final int tag, final CodedInputStream input) + throws IOException { + ensureInitializedButNotBuilt(); + + final int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + output.writeUInt64(fieldNumber, input.readInt64()); + return true; + case WireFormat.WIRETYPE_FIXED32: + output.writeFixed32(fieldNumber, input.readFixed32()); + return true; + case WireFormat.WIRETYPE_FIXED64: + output.writeFixed64(fieldNumber, input.readFixed64()); + return true; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + output.writeBytes(fieldNumber, input.readBytes()); + return true; + case WireFormat.WIRETYPE_START_GROUP: + final Builder subBuilder = newBuilder(); + subBuilder.mergeFrom(input); + input.checkLastTagWas( + WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); + + output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); + subBuilder.build().writeTo(output); + output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + return true; + case WireFormat.WIRETYPE_END_GROUP: + return false; + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } + + /** + * Convenience method for merging a new field containing a single varint + * value. This is used in particular when an unknown enum value is + * encountered. + * + *

For use by generated code only. + */ + public Builder mergeVarintField(int fieldNumber, int value) { + if (fieldNumber == 0) { + throw new IllegalArgumentException("Zero is not a valid field number."); + } + ensureInitializedButNotBuilt(); + try { + output.writeUInt64(fieldNumber, value); + } catch (IOException e) { + // Should never happen. + } + return this; + } + + /** + * Convenience method for merging a length-delimited field. + * + *

For use by generated code only. + */ + public Builder mergeLengthDelimitedField( + final int fieldNumber, final ByteString value) { + if (fieldNumber == 0) { + throw new IllegalArgumentException("Zero is not a valid field number."); + } + ensureInitializedButNotBuilt(); + try { + output.writeBytes(fieldNumber, value); + } catch (IOException e) { + // Should never happen. + } + return this; + } + + /** + * Build the {@link UnknownFieldSetLite} and return it. + * + *

Once {@code build()} has been called, the {@code Builder} will no + * longer be usable. Calling any method after {@code build()} will result + * in undefined behavior and can cause a {@code IllegalStateException} to be + * thrown. + * + *

For use by generated code only. + */ + public UnknownFieldSetLite build() { + if (built) { + throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); + } + + built = true; + + final UnknownFieldSetLite result; + // If we were never initialized, no data was written. + if (output == null) { + result = getDefaultInstance(); + } else { + try { + output.flush(); + } catch (IOException e) { + // Should never happen. + } + ByteString byteString = byteStringOutput.toByteString(); + if (byteString.isEmpty()) { + result = getDefaultInstance(); + } else { + result = new UnknownFieldSetLite(byteString); + } + } + + // Allow for garbage collection. + output = null; + byteStringOutput = null; + return result; + } + + /** + * Parse an entire message from {@code input} and merge its fields into + * this set. + */ + private Builder mergeFrom(final CodedInputStream input) throws IOException { + // Ensures initialization in mergeFieldFrom. + while (true) { + final int tag = input.readTag(); + if (tag == 0 || !mergeFieldFrom(tag, input)) { + break; + } + } + return this; + } + } +} diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java index 3f656e25..18d8142c 100644 --- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -455,19 +455,19 @@ public class CodedInputStreamTest extends TestCase { } public void testMaliciousRecursion() throws Exception { - ByteString data64 = makeRecursiveMessage(64).toByteString(); - ByteString data65 = makeRecursiveMessage(65).toByteString(); + ByteString data100 = makeRecursiveMessage(100).toByteString(); + ByteString data101 = makeRecursiveMessage(101).toByteString(); - assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64); + assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100); try { - TestRecursiveMessage.parseFrom(data65); + TestRecursiveMessage.parseFrom(data101); fail("Should have thrown an exception!"); } catch (InvalidProtocolBufferException e) { // success. } - CodedInputStream input = data64.newCodedInput(); + CodedInputStream input = data100.newCodedInput(); input.setRecursionLimit(8); try { TestRecursiveMessage.parseFrom(input); diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java index 0092771b..05832a12 100644 --- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -706,6 +706,12 @@ public class DescriptorsTest extends TestCase { assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)); } + public void testToString() { + assertEquals("protobuf_unittest.TestAllTypes.optional_uint64", + UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber( + UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString()); + } + public void testPackedEnumField() throws Exception { FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder() .setName("foo.proto") diff --git a/java/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/src/test/java/com/google/protobuf/FieldPresenceTest.java new file mode 100644 index 00000000..acf2b023 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/FieldPresenceTest.java @@ -0,0 +1,363 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; +import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly; +import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly; +import protobuf_unittest.UnittestProto; + +import junit.framework.TestCase; + +/** + * Unit tests for protos that doesn't support field presence test for optional + * non-message fields. + */ +public class FieldPresenceTest extends TestCase { + private static boolean hasMethod(Class clazz, String name) { + try { + if (clazz.getMethod(name, new Class[]{}) != null) { + return true; + } else { + return false; + } + } catch (NoSuchMethodException e) { + return false; + } + } + + private static boolean isHasMethodRemoved( + Class classWithFieldPresence, + Class classWithoutFieldPresence, + String camelName) { + return hasMethod(classWithFieldPresence, "get" + camelName) + && hasMethod(classWithFieldPresence, "has" + camelName) + && hasMethod(classWithoutFieldPresence, "get" + camelName) + && !hasMethod(classWithoutFieldPresence, "has" + camelName); + } + + public void testHasMethod() { + // Optional non-message fields don't have a hasFoo() method generated. + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OptionalInt32")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OptionalString")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OptionalBytes")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OptionalNestedEnum")); + + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OptionalInt32")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OptionalString")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OptionalBytes")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OptionalNestedEnum")); + + // message fields still have the hasFoo() method generated. + assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage()); + assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage()); + + // oneof fields don't have hasFoo() methods (even for message types). + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OneofUint32")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OneofString")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OneofBytes")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.class, + TestAllTypes.class, + "OneofNestedMessage")); + + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OneofUint32")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OneofString")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OneofBytes")); + assertTrue(isHasMethodRemoved( + UnittestProto.TestAllTypes.Builder.class, + TestAllTypes.Builder.class, + "OneofNestedMessage")); + } + + public void testFieldPresence() { + // Optional non-message fields set to their default value are treated the + // same way as not set. + + // Serialization will ignore such fields. + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalInt32(0); + builder.setOptionalString(""); + builder.setOptionalBytes(ByteString.EMPTY); + builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO); + TestAllTypes message = builder.build(); + assertEquals(0, message.getSerializedSize()); + + // mergeFrom() will ignore such fields. + TestAllTypes.Builder a = TestAllTypes.newBuilder(); + a.setOptionalInt32(1); + a.setOptionalString("x"); + a.setOptionalBytes(ByteString.copyFromUtf8("y")); + a.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR); + TestAllTypes.Builder b = TestAllTypes.newBuilder(); + b.setOptionalInt32(0); + b.setOptionalString(""); + b.setOptionalBytes(ByteString.EMPTY); + b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO); + a.mergeFrom(b.build()); + message = a.build(); + assertEquals(1, message.getOptionalInt32()); + assertEquals("x", message.getOptionalString()); + assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes()); + assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); + + // equals()/hashCode() should produce the same results. + TestAllTypes empty = TestAllTypes.newBuilder().build(); + message = builder.build(); + assertTrue(empty.equals(message)); + assertTrue(message.equals(empty)); + assertEquals(empty.hashCode(), message.hashCode()); + } + + public void testFieldPresenceByReflection() { + Descriptor descriptor = TestAllTypes.getDescriptor(); + FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32"); + FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string"); + FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes"); + FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); + + // Field not present. + TestAllTypes message = TestAllTypes.newBuilder().build(); + assertFalse(message.hasField(optionalInt32Field)); + assertFalse(message.hasField(optionalStringField)); + assertFalse(message.hasField(optionalBytesField)); + assertFalse(message.hasField(optionalNestedEnumField)); + assertEquals(0, message.getAllFields().size()); + + // Field set to default value is seen as not present. + message = TestAllTypes.newBuilder() + .setOptionalInt32(0) + .setOptionalString("") + .setOptionalBytes(ByteString.EMPTY) + .setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO) + .build(); + assertFalse(message.hasField(optionalInt32Field)); + assertFalse(message.hasField(optionalStringField)); + assertFalse(message.hasField(optionalBytesField)); + assertFalse(message.hasField(optionalNestedEnumField)); + assertEquals(0, message.getAllFields().size()); + + // Field set to non-default value is seen as present. + message = TestAllTypes.newBuilder() + .setOptionalInt32(1) + .setOptionalString("x") + .setOptionalBytes(ByteString.copyFromUtf8("y")) + .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR) + .build(); + assertTrue(message.hasField(optionalInt32Field)); + assertTrue(message.hasField(optionalStringField)); + assertTrue(message.hasField(optionalBytesField)); + assertTrue(message.hasField(optionalNestedEnumField)); + assertEquals(4, message.getAllFields().size()); + } + + public void testMessageField() { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + assertFalse(builder.hasOptionalNestedMessage()); + assertFalse(builder.build().hasOptionalNestedMessage()); + + TestAllTypes.NestedMessage.Builder nestedBuilder = + builder.getOptionalNestedMessageBuilder(); + assertTrue(builder.hasOptionalNestedMessage()); + assertTrue(builder.build().hasOptionalNestedMessage()); + + nestedBuilder.setValue(1); + assertEquals(1, builder.build().getOptionalNestedMessage().getValue()); + + builder.clearOptionalNestedMessage(); + assertFalse(builder.hasOptionalNestedMessage()); + assertFalse(builder.build().hasOptionalNestedMessage()); + + // Unlike non-message fields, if we set a message field to its default value (i.e., + // default instance), the field should be seen as present. + builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); + assertTrue(builder.hasOptionalNestedMessage()); + assertTrue(builder.build().hasOptionalNestedMessage()); + } + + public void testSerializeAndParse() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalInt32(1234); + builder.setOptionalString("hello"); + builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); + // Set an oneof field to its default value and expect it to be serialized (i.e., + // an oneof field set to the default value should be treated as present). + builder.setOneofInt32(0); + ByteString data = builder.build().toByteString(); + + TestAllTypes message = TestAllTypes.parseFrom(data); + assertEquals(1234, message.getOptionalInt32()); + assertEquals("hello", message.getOptionalString()); + // Fields not set will have the default value. + assertEquals(ByteString.EMPTY, message.getOptionalBytes()); + assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum()); + // The message field is set despite that it's set with a default instance. + assertTrue(message.hasOptionalNestedMessage()); + assertEquals(0, message.getOptionalNestedMessage().getValue()); + // The oneof field set to its default value is also present. + assertEquals( + TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase()); + } + + // Regression test for b/16173397 + // Make sure we haven't screwed up the code generation for repeated fields. + public void testRepeatedFields() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalInt32(1234); + builder.setOptionalString("hello"); + builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); + builder.addRepeatedInt32(4321); + builder.addRepeatedString("world"); + builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); + ByteString data = builder.build().toByteString(); + + TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data); + assertEquals(1234, optionalOnlyMessage.getOptionalInt32()); + assertEquals("hello", optionalOnlyMessage.getOptionalString()); + assertTrue(optionalOnlyMessage.hasOptionalNestedMessage()); + assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue()); + + TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data); + assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count()); + assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0)); + assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount()); + assertEquals("world", repeatedOnlyMessage.getRepeatedString(0)); + assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount()); + assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue()); + } + + public void testIsInitialized() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + + // Test optional proto2 message fields. + UnittestProto.TestRequired.Builder proto2Builder = + builder.getOptionalProto2MessageBuilder(); + assertFalse(builder.isInitialized()); + assertFalse(builder.buildPartial().isInitialized()); + + proto2Builder.setA(1).setB(2).setC(3); + assertTrue(builder.isInitialized()); + assertTrue(builder.buildPartial().isInitialized()); + + // Test oneof proto2 message fields. + proto2Builder = builder.getOneofProto2MessageBuilder(); + assertFalse(builder.isInitialized()); + assertFalse(builder.buildPartial().isInitialized()); + + proto2Builder.setA(1).setB(2).setC(3); + assertTrue(builder.isInitialized()); + assertTrue(builder.buildPartial().isInitialized()); + + // Test repeated proto2 message fields. + proto2Builder = builder.addRepeatedProto2MessageBuilder(); + assertFalse(builder.isInitialized()); + assertFalse(builder.buildPartial().isInitialized()); + + proto2Builder.setA(1).setB(2).setC(3); + assertTrue(builder.isInitialized()); + assertTrue(builder.buildPartial().isInitialized()); + } + + + // Test that unknown fields are dropped. + public void testUnknownFields() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalInt32(1234); + builder.addRepeatedInt32(5678); + TestAllTypes message = builder.build(); + ByteString data = message.toByteString(); + + TestOptionalFieldsOnly optionalOnlyMessage = + TestOptionalFieldsOnly.parseFrom(data); + // UnknownFieldSet should be empty. + assertEquals( + 0, optionalOnlyMessage.getUnknownFields().toByteString().size()); + assertEquals(1234, optionalOnlyMessage.getOptionalInt32()); + message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString()); + assertEquals(1234, message.getOptionalInt32()); + // The repeated field is discarded because it's unknown to the optional-only + // message. + assertEquals(0, message.getRepeatedInt32Count()); + + DynamicMessage dynamicOptionalOnlyMessage = + DynamicMessage.getDefaultInstance( + TestOptionalFieldsOnly.getDescriptor()) + .getParserForType().parseFrom(data); + assertEquals( + 0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size()); + assertEquals(optionalOnlyMessage.toByteString(), + dynamicOptionalOnlyMessage.toByteString()); + } +} diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 0b3482c3..41ed7bd0 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -157,15 +157,12 @@ public class GeneratedMessageTest extends TestCase { public void testProtosShareRepeatedArraysIfDidntChange() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); builder.addRepeatedInt32(100); - builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR); builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance()); TestAllTypes value1 = builder.build(); TestAllTypes value2 = value1.toBuilder().build(); assertSame(value1.getRepeatedInt32List(), value2.getRepeatedInt32List()); - assertSame(value1.getRepeatedImportEnumList(), - value2.getRepeatedImportEnumList()); assertSame(value1.getRepeatedForeignMessageList(), value2.getRepeatedForeignMessageList()); } @@ -1512,4 +1509,142 @@ public class GeneratedMessageTest extends TestCase { assertEquals(message2.getFooMessage().getQuxInt(), 234); } } + + public void testGetRepeatedFieldBuilder() { + Descriptor descriptor = TestAllTypes.getDescriptor(); + + FieldDescriptor fieldDescriptor = + descriptor.findFieldByName("repeated_nested_message"); + FieldDescriptor foreignFieldDescriptor = + descriptor.findFieldByName("repeated_foreign_message"); + FieldDescriptor importFieldDescriptor = + descriptor.findFieldByName("repeated_import_message"); + + // Mutate the message with new field builder + // Mutate nested message + TestAllTypes.Builder builder1 = TestAllTypes.newBuilder(); + Message.Builder fieldBuilder1 = builder1.newBuilderForField( + fieldDescriptor); + FieldDescriptor subFieldDescriptor1 = + fieldBuilder1.getDescriptorForType().findFieldByName("bb"); + fieldBuilder1.setField(subFieldDescriptor1, 1); + builder1.addRepeatedField(fieldDescriptor, fieldBuilder1.build()); + + // Mutate foreign message + Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField( + foreignFieldDescriptor); + FieldDescriptor subForeignFieldDescriptor1 = + foreignFieldBuilder1.getDescriptorForType().findFieldByName("c"); + foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2); + builder1.addRepeatedField(foreignFieldDescriptor, + foreignFieldBuilder1.build()); + + // Mutate import message + Message.Builder importFieldBuilder1 = builder1.newBuilderForField( + importFieldDescriptor); + FieldDescriptor subImportFieldDescriptor1 = + importFieldBuilder1.getDescriptorForType().findFieldByName("d"); + importFieldBuilder1.setField(subImportFieldDescriptor1, 3); + builder1.addRepeatedField(importFieldDescriptor, + importFieldBuilder1.build()); + + Message newMessage1 = builder1.build(); + + // Mutate the message with existing field builder + // Mutate nested message + TestAllTypes.Builder builder2 = TestAllTypes.newBuilder(); + builder2.addRepeatedNestedMessageBuilder(); + Message.Builder fieldBuilder2 = builder2.getRepeatedFieldBuilder( + fieldDescriptor, 0); + FieldDescriptor subFieldDescriptor2 = + fieldBuilder2.getDescriptorForType().findFieldByName("bb"); + fieldBuilder2.setField(subFieldDescriptor2, 1); + + // Mutate foreign message + Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField( + foreignFieldDescriptor); + FieldDescriptor subForeignFieldDescriptor2 = + foreignFieldBuilder2.getDescriptorForType().findFieldByName("c"); + foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2); + builder2.addRepeatedField(foreignFieldDescriptor, + foreignFieldBuilder2.build()); + + // Mutate import message + Message.Builder importFieldBuilder2 = builder2.newBuilderForField( + importFieldDescriptor); + FieldDescriptor subImportFieldDescriptor2 = + importFieldBuilder2.getDescriptorForType().findFieldByName("d"); + importFieldBuilder2.setField(subImportFieldDescriptor2, 3); + builder2.addRepeatedField(importFieldDescriptor, + importFieldBuilder2.build()); + + Message newMessage2 = builder2.build(); + + // These two messages should be equal. + assertEquals(newMessage1, newMessage2); + } + + public void testGetRepeatedFieldBuilderWithInitializedValue() { + Descriptor descriptor = TestAllTypes.getDescriptor(); + FieldDescriptor fieldDescriptor = + descriptor.findFieldByName("repeated_nested_message"); + + // Before setting field, builder is initialized by default value. + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.addRepeatedNestedMessageBuilder(); + NestedMessage.Builder fieldBuilder = + (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0); + assertEquals(0, fieldBuilder.getBb()); + + // Setting field value with new field builder instance. + builder = TestAllTypes.newBuilder(); + NestedMessage.Builder newFieldBuilder = + builder.addRepeatedNestedMessageBuilder(); + newFieldBuilder.setBb(2); + // Then get the field builder instance by getRepeatedFieldBuilder(). + fieldBuilder = + (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0); + // It should contain new value. + assertEquals(2, fieldBuilder.getBb()); + // These two builder should be equal. + assertSame(fieldBuilder, newFieldBuilder); + } + + public void testGetRepeatedFieldBuilderNotSupportedException() { + Descriptor descriptor = TestAllTypes.getDescriptor(); + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + try { + builder.getRepeatedFieldBuilder(descriptor.findFieldByName("repeated_int32"), 0); + fail("Exception was not thrown"); + } catch (UnsupportedOperationException e) { + // We expect this exception. + } + try { + builder.getRepeatedFieldBuilder( + descriptor.findFieldByName("repeated_nested_enum"), 0); + fail("Exception was not thrown"); + } catch (UnsupportedOperationException e) { + // We expect this exception. + } + try { + builder.getRepeatedFieldBuilder(descriptor.findFieldByName("optional_int32"), 0); + fail("Exception was not thrown"); + } catch (UnsupportedOperationException e) { + // We expect this exception. + } + try { + builder.getRepeatedFieldBuilder( + descriptor.findFieldByName("optional_nested_enum"), 0); + fail("Exception was not thrown"); + } catch (UnsupportedOperationException e) { + // We expect this exception. + } + try { + builder.getRepeatedFieldBuilder( + descriptor.findFieldByName("optional_nested_message"), 0); + fail("Exception was not thrown"); + } catch (UnsupportedOperationException e) { + // We expect this exception. + } + } } diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java index 00e3a843..9de794fe 100644 --- a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java +++ b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java @@ -36,8 +36,6 @@ import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite; import junit.framework.TestCase; -import org.easymock.classextension.EasyMock; - import java.util.ArrayList; /** @@ -52,14 +50,10 @@ public class LazyMessageLiteTest extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); - - originalLazyInnerMessageLiteParser = LazyInnerMessageLite.PARSER; } @Override protected void tearDown() throws Exception { - LazyInnerMessageLite.PARSER = originalLazyInnerMessageLiteParser; - super.tearDown(); } @@ -291,29 +285,4 @@ public class LazyMessageLiteTest extends TestCase { assertEquals(bytes, deserialized.toByteString()); } - - public void testLaziness() throws InvalidProtocolBufferException { - LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() - .setNum(2) - .build(); - LazyMessageLite outer = LazyMessageLite.newBuilder() - .setNum(1) - .setInner(inner) - .setOneofInner(inner) - .build(); - ByteString bytes = outer.toByteString(); - - - // The parser for inner / oneofInner message shouldn't be used if - // getInner / getOneofInner is not called. - LazyInnerMessageLite.PARSER = EasyMock.createStrictMock(Parser.class); - - EasyMock.replay(LazyInnerMessageLite.PARSER); - - LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes); - assertEquals(1, deserialized.getNum()); - assertEquals(421, deserialized.getNumWithDefault()); - - EasyMock.verify(LazyInnerMessageLite.PARSER); - } } diff --git a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java index 94f4fcf5..035917c8 100644 --- a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java +++ b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java @@ -82,4 +82,27 @@ public class LiteEqualsAndHashTest extends TestCase { BarPrime barPrime = BarPrime.newBuilder().setName("bar").build(); assertFalse(bar.equals(barPrime)); } + + public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException { + Foo fooWithOnlyValue = Foo.newBuilder() + .setValue(1) + .build(); + + Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder() + .setName("name") + .build()) + .build(); + + Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray()); + + assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields); + assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields); + } + + private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) { + assertFalse(o1.equals(o2)); + assertFalse(o1.hashCode() == o2.hashCode()); + } } diff --git a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java new file mode 100644 index 00000000..22dbeb76 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java @@ -0,0 +1,277 @@ +// 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. + +package com.google.protobuf; + +import map_lite_test.MapForProto2TestProto.TestMap; +import map_lite_test.MapForProto2TestProto.TestMap.MessageValue; +import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue; + +import junit.framework.TestCase; + +/** + * Unit tests for map fields. + */ +public class MapForProto2LiteTest extends TestCase { + private void setMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 11); + builder.getMutableInt32ToInt32Field().put(2, 22); + builder.getMutableInt32ToInt32Field().put(3, 33); + + builder.getMutableInt32ToStringField().put(1, "11"); + builder.getMutableInt32ToStringField().put(2, "22"); + builder.getMutableInt32ToStringField().put(3, "33"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); + builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); + builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(11).build()); + builder.getMutableInt32ToMessageField().put( + 2, MessageValue.newBuilder().setValue(22).build()); + builder.getMutableInt32ToMessageField().put( + 3, MessageValue.newBuilder().setValue(33).build()); + + builder.getMutableStringToInt32Field().put("1", 11); + builder.getMutableStringToInt32Field().put("2", 22); + builder.getMutableStringToInt32Field().put("3", 33); + } + + private void assertMapValuesSet(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("11", message.getInt32ToStringField().get(1)); + assertEquals("22", message.getInt32ToStringField().get(2)); + assertEquals("33", message.getInt32ToStringField().get(3)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(11, message.getStringToInt32Field().get("1").intValue()); + assertEquals(22, message.getStringToInt32Field().get("2").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + } + + private void updateMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 111); + builder.getMutableInt32ToInt32Field().remove(2); + builder.getMutableInt32ToInt32Field().put(4, 44); + + builder.getMutableInt32ToStringField().put(1, "111"); + builder.getMutableInt32ToStringField().remove(2); + builder.getMutableInt32ToStringField().put(4, "44"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); + builder.getMutableInt32ToBytesField().remove(2); + builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().remove(2); + builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(111).build()); + builder.getMutableInt32ToMessageField().remove(2); + builder.getMutableInt32ToMessageField().put( + 4, MessageValue.newBuilder().setValue(44).build()); + + builder.getMutableStringToInt32Field().put("1", 111); + builder.getMutableStringToInt32Field().remove("2"); + builder.getMutableStringToInt32Field().put("4", 44); + } + + private void assertMapValuesUpdated(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("111", message.getInt32ToStringField().get(1)); + assertEquals("33", message.getInt32ToStringField().get(3)); + assertEquals("44", message.getInt32ToStringField().get(4)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(111, message.getStringToInt32Field().get("1").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + assertEquals(44, message.getStringToInt32Field().get("4").intValue()); + } + + private void assertMapValuesCleared(TestMap message) { + assertEquals(0, message.getInt32ToInt32Field().size()); + assertEquals(0, message.getInt32ToStringField().size()); + assertEquals(0, message.getInt32ToBytesField().size()); + assertEquals(0, message.getInt32ToEnumField().size()); + assertEquals(0, message.getInt32ToMessageField().size()); + assertEquals(0, message.getStringToInt32Field().size()); + } + + public void testGettersAndSetters() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + assertMapValuesCleared(message); + + builder = message.toBuilder(); + setMapValues(builder); + message = builder.build(); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertMapValuesCleared(message); + } + + public void testSerializeAndParse() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesCleared(message); + } + + public void testMergeFrom() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + TestMap.Builder other = TestMap.newBuilder(); + other.mergeFrom(message); + assertMapValuesSet(other.build()); + } + + public void testEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We can't control the order of elements in a HashMap. The best we can do + // here is to add elements in different order. + TestMap.Builder b1 = TestMap.newBuilder(); + b1.getMutableInt32ToInt32Field().put(1, 2); + b1.getMutableInt32ToInt32Field().put(3, 4); + b1.getMutableInt32ToInt32Field().put(5, 6); + TestMap m1 = b1.build(); + + TestMap.Builder b2 = TestMap.newBuilder(); + b2.getMutableInt32ToInt32Field().put(5, 6); + b2.getMutableInt32ToInt32Field().put(1, 2); + b2.getMutableInt32ToInt32Field().put(3, 4); + TestMap m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.getMutableInt32ToInt32Field().put(1, 0); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + } + + public void testUnknownEnumValues() throws Exception { + TestUnknownEnumValue.Builder builder = + TestUnknownEnumValue.newBuilder(); + builder.getMutableInt32ToInt32Field().put(1, 1); + builder.getMutableInt32ToInt32Field().put(2, 54321); + ByteString data = builder.build().toByteString(); + + TestMap message = TestMap.parseFrom(data); + // Entries with unknown enum values will be stored into UnknownFieldSet so + // there is only one entry in the map. + assertEquals(1, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + // Serializing and parsing should preserve the unknown entry. + data = message.toByteString(); + TestUnknownEnumValue messageWithUnknownEnums = + TestUnknownEnumValue.parseFrom(data); + assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); + assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); + assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); + } + +} diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/src/test/java/com/google/protobuf/MapForProto2Test.java new file mode 100644 index 00000000..d78c0d94 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/MapForProto2Test.java @@ -0,0 +1,488 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.FieldDescriptor; +import map_test.MapForProto2TestProto.TestMap; +import map_test.MapForProto2TestProto.TestMap.MessageValue; +import map_test.MapForProto2TestProto.TestUnknownEnumValue; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Unit tests for map fields in proto2 protos. + */ +public class MapForProto2Test extends TestCase { + private void setMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 11); + builder.getMutableInt32ToInt32Field().put(2, 22); + builder.getMutableInt32ToInt32Field().put(3, 33); + + builder.getMutableInt32ToStringField().put(1, "11"); + builder.getMutableInt32ToStringField().put(2, "22"); + builder.getMutableInt32ToStringField().put(3, "33"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); + builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); + builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(11).build()); + builder.getMutableInt32ToMessageField().put( + 2, MessageValue.newBuilder().setValue(22).build()); + builder.getMutableInt32ToMessageField().put( + 3, MessageValue.newBuilder().setValue(33).build()); + + builder.getMutableStringToInt32Field().put("1", 11); + builder.getMutableStringToInt32Field().put("2", 22); + builder.getMutableStringToInt32Field().put("3", 33); + } + + private void assertMapValuesSet(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("11", message.getInt32ToStringField().get(1)); + assertEquals("22", message.getInt32ToStringField().get(2)); + assertEquals("33", message.getInt32ToStringField().get(3)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(11, message.getStringToInt32Field().get("1").intValue()); + assertEquals(22, message.getStringToInt32Field().get("2").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + } + + private void updateMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 111); + builder.getMutableInt32ToInt32Field().remove(2); + builder.getMutableInt32ToInt32Field().put(4, 44); + + builder.getMutableInt32ToStringField().put(1, "111"); + builder.getMutableInt32ToStringField().remove(2); + builder.getMutableInt32ToStringField().put(4, "44"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); + builder.getMutableInt32ToBytesField().remove(2); + builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().remove(2); + builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(111).build()); + builder.getMutableInt32ToMessageField().remove(2); + builder.getMutableInt32ToMessageField().put( + 4, MessageValue.newBuilder().setValue(44).build()); + + builder.getMutableStringToInt32Field().put("1", 111); + builder.getMutableStringToInt32Field().remove("2"); + builder.getMutableStringToInt32Field().put("4", 44); + } + + private void assertMapValuesUpdated(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("111", message.getInt32ToStringField().get(1)); + assertEquals("33", message.getInt32ToStringField().get(3)); + assertEquals("44", message.getInt32ToStringField().get(4)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(111, message.getStringToInt32Field().get("1").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + assertEquals(44, message.getStringToInt32Field().get("4").intValue()); + } + + private void assertMapValuesCleared(TestMap message) { + assertEquals(0, message.getInt32ToInt32Field().size()); + assertEquals(0, message.getInt32ToStringField().size()); + assertEquals(0, message.getInt32ToBytesField().size()); + assertEquals(0, message.getInt32ToEnumField().size()); + assertEquals(0, message.getInt32ToMessageField().size()); + assertEquals(0, message.getStringToInt32Field().size()); + } + + public void testGettersAndSetters() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + assertMapValuesCleared(message); + + builder = message.toBuilder(); + setMapValues(builder); + message = builder.build(); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertMapValuesCleared(message); + } + + public void testSerializeAndParse() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesCleared(message); + } + + public void testMergeFrom() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + TestMap.Builder other = TestMap.newBuilder(); + other.mergeFrom(message); + assertMapValuesSet(other.build()); + } + + public void testEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We can't control the order of elements in a HashMap. The best we can do + // here is to add elements in different order. + TestMap.Builder b1 = TestMap.newBuilder(); + b1.getMutableInt32ToInt32Field().put(1, 2); + b1.getMutableInt32ToInt32Field().put(3, 4); + b1.getMutableInt32ToInt32Field().put(5, 6); + TestMap m1 = b1.build(); + + TestMap.Builder b2 = TestMap.newBuilder(); + b2.getMutableInt32ToInt32Field().put(5, 6); + b2.getMutableInt32ToInt32Field().put(1, 2); + b2.getMutableInt32ToInt32Field().put(3, 4); + TestMap m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.getMutableInt32ToInt32Field().put(1, 0); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + } + + + // The following methods are used to test reflection API. + + private static FieldDescriptor f(String name) { + return TestMap.getDescriptor().findFieldByName(name); + } + + private static Object getFieldValue(Message mapEntry, String name) { + FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); + return mapEntry.getField(field); + } + + private static Message.Builder setFieldValue( + Message.Builder mapEntry, String name, Object value) { + FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); + mapEntry.setField(field, value); + return mapEntry; + } + + private static void assertHasMapValues(Message message, String name, Map values) { + FieldDescriptor field = f(name); + for (Object entry : (List) message.getField(field)) { + Message mapEntry = (Message) entry; + Object key = getFieldValue(mapEntry, "key"); + Object value = getFieldValue(mapEntry, "value"); + assertTrue(values.containsKey(key)); + assertEquals(value, values.get(key)); + } + assertEquals(values.size(), message.getRepeatedFieldCount(field)); + for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { + Message mapEntry = (Message) message.getRepeatedField(field, i); + Object key = getFieldValue(mapEntry, "key"); + Object value = getFieldValue(mapEntry, "value"); + assertTrue(values.containsKey(key)); + assertEquals(value, values.get(key)); + } + } + + private static + Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { + FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); + Message.Builder entryBuilder = builder.newBuilderForField(field); + FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); + FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); + entryBuilder.setField(keyField, key); + entryBuilder.setField(valueField, value); + return entryBuilder.build(); + } + + private static void setMapValues(Message.Builder builder, String name, Map values) { + List entryList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); + } + FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); + builder.setField(field, entryList); + } + + private static + Map mapForValues( + KeyType key1, ValueType value1, KeyType key2, ValueType value2) { + Map map = new HashMap(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } + + public void testReflectionApi() throws Exception { + // In reflection API, map fields are just repeated message fields. + TestMap.Builder builder = TestMap.newBuilder(); + builder.getMutableInt32ToInt32Field().put(1, 2); + builder.getMutableInt32ToInt32Field().put(3, 4); + builder.getMutableInt32ToMessageField().put( + 11, MessageValue.newBuilder().setValue(22).build()); + builder.getMutableInt32ToMessageField().put( + 33, MessageValue.newBuilder().setValue(44).build()); + TestMap message = builder.build(); + + // Test getField(), getRepeatedFieldCount(), getRepeatedField(). + assertHasMapValues(message, "int32_to_int32_field", + mapForValues(1, 2, 3, 4)); + assertHasMapValues(message, "int32_to_message_field", + mapForValues( + 11, MessageValue.newBuilder().setValue(22).build(), + 33, MessageValue.newBuilder().setValue(44).build())); + + // Test clearField() + builder.clearField(f("int32_to_int32_field")); + builder.clearField(f("int32_to_message_field")); + message = builder.build(); + assertEquals(0, message.getInt32ToInt32Field().size()); + assertEquals(0, message.getInt32ToMessageField().size()); + + // Test setField() + setMapValues(builder, "int32_to_int32_field", + mapForValues(11, 22, 33, 44)); + setMapValues(builder, "int32_to_message_field", + mapForValues( + 111, MessageValue.newBuilder().setValue(222).build(), + 333, MessageValue.newBuilder().setValue(444).build())); + message = builder.build(); + assertEquals(22, message.getInt32ToInt32Field().get(11).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(33).intValue()); + assertEquals(222, message.getInt32ToMessageField().get(111).getValue()); + assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); + + // Test addRepeatedField + builder.addRepeatedField(f("int32_to_int32_field"), + newMapEntry(builder, "int32_to_int32_field", 55, 66)); + builder.addRepeatedField(f("int32_to_message_field"), + newMapEntry(builder, "int32_to_message_field", 555, + MessageValue.newBuilder().setValue(666).build())); + message = builder.build(); + assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); + assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); + + // Test addRepeatedField (overriding existing values) + builder.addRepeatedField(f("int32_to_int32_field"), + newMapEntry(builder, "int32_to_int32_field", 55, 55)); + builder.addRepeatedField(f("int32_to_message_field"), + newMapEntry(builder, "int32_to_message_field", 555, + MessageValue.newBuilder().setValue(555).build())); + message = builder.build(); + assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); + assertEquals(555, message.getInt32ToMessageField().get(555).getValue()); + + // Test setRepeatedField + for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { + Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); + int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); + int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); + // Swap key with value for each entry. + Message.Builder mapEntryBuilder = mapEntry.toBuilder(); + setFieldValue(mapEntryBuilder, "key", oldValue); + setFieldValue(mapEntryBuilder, "value", oldKey); + builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); + } + message = builder.build(); + assertEquals(11, message.getInt32ToInt32Field().get(22).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); + assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); + } + + public void testTextFormat() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + String textData = TextFormat.printToString(message); + + builder = TestMap.newBuilder(); + TextFormat.merge(textData, builder); + message = builder.build(); + + assertMapValuesSet(message); + } + + public void testDynamicMessage() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + Message dynamicDefaultInstance = + DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); + Message dynamicMessage = dynamicDefaultInstance + .newBuilderForType().mergeFrom(message.toByteString()).build(); + + assertEquals(message, dynamicMessage); + assertEquals(message.hashCode(), dynamicMessage.hashCode()); + } + + public void testReflectionEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We use DynamicMessage to test reflection based equals()/hashCode(). + Message dynamicDefaultInstance = + DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); + FieldDescriptor field = f("int32_to_int32_field"); + + Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); + Message m1 = b1.build(); + + Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); + Message m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + } + + public void testUnknownEnumValues() throws Exception { + TestUnknownEnumValue.Builder builder = + TestUnknownEnumValue.newBuilder(); + builder.getMutableInt32ToInt32Field().put(1, 1); + builder.getMutableInt32ToInt32Field().put(2, 54321); + ByteString data = builder.build().toByteString(); + + TestMap message = TestMap.parseFrom(data); + // Entries with unknown enum values will be stored into UnknownFieldSet so + // there is only one entry in the map. + assertEquals(1, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + // UnknownFieldSet should not be empty. + assertFalse(message.getUnknownFields().asMap().isEmpty()); + // Serializing and parsing should preserve the unknown entry. + data = message.toByteString(); + TestUnknownEnumValue messageWithUnknownEnums = + TestUnknownEnumValue.parseFrom(data); + assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); + assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); + assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); + } + +} diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java new file mode 100644 index 00000000..542a20e7 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/MapTest.java @@ -0,0 +1,569 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.EnumDescriptor; +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import map_test.MapTestProto.TestMap; +import map_test.MapTestProto.TestMap.MessageValue; +import map_test.MapTestProto.TestOnChangeEventPropagation; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Unit tests for map fields. + */ +public class MapTest extends TestCase { + private void setMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 11); + builder.getMutableInt32ToInt32Field().put(2, 22); + builder.getMutableInt32ToInt32Field().put(3, 33); + + builder.getMutableInt32ToStringField().put(1, "11"); + builder.getMutableInt32ToStringField().put(2, "22"); + builder.getMutableInt32ToStringField().put(3, "33"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); + builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); + builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(11).build()); + builder.getMutableInt32ToMessageField().put( + 2, MessageValue.newBuilder().setValue(22).build()); + builder.getMutableInt32ToMessageField().put( + 3, MessageValue.newBuilder().setValue(33).build()); + + builder.getMutableStringToInt32Field().put("1", 11); + builder.getMutableStringToInt32Field().put("2", 22); + builder.getMutableStringToInt32Field().put("3", 33); + } + + private void assertMapValuesSet(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("11", message.getInt32ToStringField().get(1)); + assertEquals("22", message.getInt32ToStringField().get(2)); + assertEquals("33", message.getInt32ToStringField().get(3)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(11, message.getStringToInt32Field().get("1").intValue()); + assertEquals(22, message.getStringToInt32Field().get("2").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + } + + private void updateMapValues(TestMap.Builder builder) { + builder.getMutableInt32ToInt32Field().put(1, 111); + builder.getMutableInt32ToInt32Field().remove(2); + builder.getMutableInt32ToInt32Field().put(4, 44); + + builder.getMutableInt32ToStringField().put(1, "111"); + builder.getMutableInt32ToStringField().remove(2); + builder.getMutableInt32ToStringField().put(4, "44"); + + builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); + builder.getMutableInt32ToBytesField().remove(2); + builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); + + builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); + builder.getMutableInt32ToEnumField().remove(2); + builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); + + builder.getMutableInt32ToMessageField().put( + 1, MessageValue.newBuilder().setValue(111).build()); + builder.getMutableInt32ToMessageField().remove(2); + builder.getMutableInt32ToMessageField().put( + 4, MessageValue.newBuilder().setValue(44).build()); + + builder.getMutableStringToInt32Field().put("1", 111); + builder.getMutableStringToInt32Field().remove("2"); + builder.getMutableStringToInt32Field().put("4", 44); + } + + private void assertMapValuesUpdated(TestMap message) { + assertEquals(3, message.getInt32ToInt32Field().size()); + assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); + + assertEquals(3, message.getInt32ToStringField().size()); + assertEquals("111", message.getInt32ToStringField().get(1)); + assertEquals("33", message.getInt32ToStringField().get(3)); + assertEquals("44", message.getInt32ToStringField().get(4)); + + assertEquals(3, message.getInt32ToBytesField().size()); + assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); + assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); + assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); + + assertEquals(3, message.getInt32ToEnumField().size()); + assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); + assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); + + assertEquals(3, message.getInt32ToMessageField().size()); + assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); + assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); + assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); + + assertEquals(3, message.getStringToInt32Field().size()); + assertEquals(111, message.getStringToInt32Field().get("1").intValue()); + assertEquals(33, message.getStringToInt32Field().get("3").intValue()); + assertEquals(44, message.getStringToInt32Field().get("4").intValue()); + } + + private void assertMapValuesCleared(TestMap message) { + assertEquals(0, message.getInt32ToInt32Field().size()); + assertEquals(0, message.getInt32ToStringField().size()); + assertEquals(0, message.getInt32ToBytesField().size()); + assertEquals(0, message.getInt32ToEnumField().size()); + assertEquals(0, message.getInt32ToMessageField().size()); + assertEquals(0, message.getStringToInt32Field().size()); + } + + public void testGettersAndSetters() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + assertMapValuesCleared(message); + + builder = message.toBuilder(); + setMapValues(builder); + message = builder.build(); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertMapValuesCleared(message); + } + + public void testSerializeAndParse() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesSet(message); + + builder = message.toBuilder(); + updateMapValues(builder); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesUpdated(message); + + builder = message.toBuilder(); + builder.clear(); + message = builder.build(); + assertEquals(message.getSerializedSize(), message.toByteString().size()); + message = TestMap.PARSER.parseFrom(message.toByteString()); + assertMapValuesCleared(message); + } + + public void testMergeFrom() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + TestMap.Builder other = TestMap.newBuilder(); + other.mergeFrom(message); + assertMapValuesSet(other.build()); + } + + public void testEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We can't control the order of elements in a HashMap. The best we can do + // here is to add elements in different order. + TestMap.Builder b1 = TestMap.newBuilder(); + b1.getMutableInt32ToInt32Field().put(1, 2); + b1.getMutableInt32ToInt32Field().put(3, 4); + b1.getMutableInt32ToInt32Field().put(5, 6); + TestMap m1 = b1.build(); + + TestMap.Builder b2 = TestMap.newBuilder(); + b2.getMutableInt32ToInt32Field().put(5, 6); + b2.getMutableInt32ToInt32Field().put(1, 2); + b2.getMutableInt32ToInt32Field().put(3, 4); + TestMap m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.getMutableInt32ToInt32Field().put(1, 0); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + } + + + public void testNestedBuilderOnChangeEventPropagation() { + TestOnChangeEventPropagation.Builder parent = + TestOnChangeEventPropagation.newBuilder(); + parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 2); + TestOnChangeEventPropagation message = parent.build(); + assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); + + // Make a change using nested builder. + parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 3); + + // Should be able to observe the change. + message = parent.build(); + assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); + + // Make another change using mergeFrom() + TestMap.Builder other = TestMap.newBuilder(); + other.getMutableInt32ToInt32Field().put(1, 4); + parent.getOptionalMessageBuilder().mergeFrom(other.build()); + + // Should be able to observe the change. + message = parent.build(); + assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); + + // Make yet another change by clearing the nested builder. + parent.getOptionalMessageBuilder().clear(); + + // Should be able to observe the change. + message = parent.build(); + assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size()); + } + + // The following methods are used to test reflection API. + + private static FieldDescriptor f(String name) { + return TestMap.getDescriptor().findFieldByName(name); + } + + private static Object getFieldValue(Message mapEntry, String name) { + FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); + return mapEntry.getField(field); + } + + private static Message.Builder setFieldValue( + Message.Builder mapEntry, String name, Object value) { + FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); + mapEntry.setField(field, value); + return mapEntry; + } + + private static void assertHasMapValues(Message message, String name, Map values) { + FieldDescriptor field = f(name); + for (Object entry : (List) message.getField(field)) { + Message mapEntry = (Message) entry; + Object key = getFieldValue(mapEntry, "key"); + Object value = getFieldValue(mapEntry, "value"); + assertTrue(values.containsKey(key)); + assertEquals(value, values.get(key)); + } + assertEquals(values.size(), message.getRepeatedFieldCount(field)); + for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { + Message mapEntry = (Message) message.getRepeatedField(field, i); + Object key = getFieldValue(mapEntry, "key"); + Object value = getFieldValue(mapEntry, "value"); + assertTrue(values.containsKey(key)); + assertEquals(value, values.get(key)); + } + } + + private static + Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { + FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); + Message.Builder entryBuilder = builder.newBuilderForField(field); + FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); + FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); + entryBuilder.setField(keyField, key); + entryBuilder.setField(valueField, value); + return entryBuilder.build(); + } + + private static void setMapValues(Message.Builder builder, String name, Map values) { + List entryList = new ArrayList(); + for (Map.Entry entry : values.entrySet()) { + entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); + } + FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); + builder.setField(field, entryList); + } + + private static + Map mapForValues( + KeyType key1, ValueType value1, KeyType key2, ValueType value2) { + Map map = new HashMap(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } + + public void testReflectionApi() throws Exception { + // In reflection API, map fields are just repeated message fields. + TestMap.Builder builder = TestMap.newBuilder(); + builder.getMutableInt32ToInt32Field().put(1, 2); + builder.getMutableInt32ToInt32Field().put(3, 4); + builder.getMutableInt32ToMessageField().put( + 11, MessageValue.newBuilder().setValue(22).build()); + builder.getMutableInt32ToMessageField().put( + 33, MessageValue.newBuilder().setValue(44).build()); + TestMap message = builder.build(); + + // Test getField(), getRepeatedFieldCount(), getRepeatedField(). + assertHasMapValues(message, "int32_to_int32_field", + mapForValues(1, 2, 3, 4)); + assertHasMapValues(message, "int32_to_message_field", + mapForValues( + 11, MessageValue.newBuilder().setValue(22).build(), + 33, MessageValue.newBuilder().setValue(44).build())); + + // Test clearField() + builder.clearField(f("int32_to_int32_field")); + builder.clearField(f("int32_to_message_field")); + message = builder.build(); + assertEquals(0, message.getInt32ToInt32Field().size()); + assertEquals(0, message.getInt32ToMessageField().size()); + + // Test setField() + setMapValues(builder, "int32_to_int32_field", + mapForValues(11, 22, 33, 44)); + setMapValues(builder, "int32_to_message_field", + mapForValues( + 111, MessageValue.newBuilder().setValue(222).build(), + 333, MessageValue.newBuilder().setValue(444).build())); + message = builder.build(); + assertEquals(22, message.getInt32ToInt32Field().get(11).intValue()); + assertEquals(44, message.getInt32ToInt32Field().get(33).intValue()); + assertEquals(222, message.getInt32ToMessageField().get(111).getValue()); + assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); + + // Test addRepeatedField + builder.addRepeatedField(f("int32_to_int32_field"), + newMapEntry(builder, "int32_to_int32_field", 55, 66)); + builder.addRepeatedField(f("int32_to_message_field"), + newMapEntry(builder, "int32_to_message_field", 555, + MessageValue.newBuilder().setValue(666).build())); + message = builder.build(); + assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); + assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); + + // Test addRepeatedField (overriding existing values) + builder.addRepeatedField(f("int32_to_int32_field"), + newMapEntry(builder, "int32_to_int32_field", 55, 55)); + builder.addRepeatedField(f("int32_to_message_field"), + newMapEntry(builder, "int32_to_message_field", 555, + MessageValue.newBuilder().setValue(555).build())); + message = builder.build(); + assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); + assertEquals(555, message.getInt32ToMessageField().get(555).getValue()); + + // Test setRepeatedField + for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { + Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); + int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); + int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); + // Swap key with value for each entry. + Message.Builder mapEntryBuilder = mapEntry.toBuilder(); + setFieldValue(mapEntryBuilder, "key", oldValue); + setFieldValue(mapEntryBuilder, "value", oldKey); + builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); + } + message = builder.build(); + assertEquals(11, message.getInt32ToInt32Field().get(22).intValue()); + assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); + assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); + } + + public void testTextFormat() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + String textData = TextFormat.printToString(message); + + builder = TestMap.newBuilder(); + TextFormat.merge(textData, builder); + message = builder.build(); + + assertMapValuesSet(message); + } + + public void testDynamicMessage() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + Message dynamicDefaultInstance = + DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); + Message dynamicMessage = dynamicDefaultInstance + .newBuilderForType().mergeFrom(message.toByteString()).build(); + + assertEquals(message, dynamicMessage); + assertEquals(message.hashCode(), dynamicMessage.hashCode()); + } + + public void testReflectionEqualsAndHashCode() throws Exception { + // Test that generated equals() and hashCode() will disregard the order + // of map entries when comparing/hashing map fields. + + // We use DynamicMessage to test reflection based equals()/hashCode(). + Message dynamicDefaultInstance = + DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); + FieldDescriptor field = f("int32_to_int32_field"); + + Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); + b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); + Message m1 = b1.build(); + + Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); + b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); + Message m2 = b2.build(); + + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + // Make sure we did compare map fields. + b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); + m2 = b2.build(); + assertFalse(m1.equals(m2)); + // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed + // to be different. + } + + public void testUnknownEnumValues() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + builder.getMutableInt32ToEnumFieldValue().put(0, 0); + builder.getMutableInt32ToEnumFieldValue().put(1, 1); + builder.getMutableInt32ToEnumFieldValue().put(2, 1000); // unknown value. + TestMap message = builder.build(); + + assertEquals(TestMap.EnumValue.FOO, + message.getInt32ToEnumField().get(0)); + assertEquals(TestMap.EnumValue.BAR, + message.getInt32ToEnumField().get(1)); + assertEquals(TestMap.EnumValue.UNRECOGNIZED, + message.getInt32ToEnumField().get(2)); + assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); + + // Unknown enum values should be preserved after: + // 1. Serialization and parsing. + // 2. toBuild(). + // 3. mergeFrom(). + message = TestMap.parseFrom(message.toByteString()); + assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); + builder = message.toBuilder(); + assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); + builder = TestMap.newBuilder().mergeFrom(message); + assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); + + // hashCode()/equals() should take unknown enum values into account. + builder.getMutableInt32ToEnumFieldValue().put(2, 1001); + TestMap message2 = builder.build(); + assertFalse(message.hashCode() == message2.hashCode()); + assertFalse(message.equals(message2)); + // Unknown values will be converted to UNRECOGNIZED so the resulted enum map + // should be the same. + assertTrue(message.getInt32ToEnumField().equals(message2.getInt32ToEnumField())); + } + + public void testUnknownEnumValuesInReflectionApi() throws Exception { + Descriptor descriptor = TestMap.getDescriptor(); + EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field"); + + Map data = new HashMap(); + data.put(0, 0); + data.put(1, 1); + data.put(2, 1000); // unknown value. + + TestMap.Builder builder = TestMap.newBuilder(); + for (Map.Entry entry : data.entrySet()) { + builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue()); + } + + // Try to read unknown enum values using reflection API. + for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) { + Message mapEntry = (Message) builder.getRepeatedField(field, i); + int key = ((Integer) getFieldValue(mapEntry, "key")).intValue(); + int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber(); + assertEquals(data.get(key).intValue(), value); + Message.Builder mapEntryBuilder = mapEntry.toBuilder(); + // Increase the value by 1. + setFieldValue(mapEntryBuilder, "value", + enumDescriptor.findValueByNumberCreatingIfUnknown(value + 1)); + builder.setRepeatedField(field, i, mapEntryBuilder.build()); + } + + // Verify that enum values have been successfully updated. + TestMap message = builder.build(); + for (Map.Entry entry : message.getInt32ToEnumFieldValue().entrySet()) { + assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue()); + } + } +} diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java index 614ac7fe..2c60fe0e 100644 --- a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java +++ b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java @@ -72,7 +72,7 @@ public class TestBadIdentifiers extends TestCase { assertEquals(0, message.getMessageField5Count()); assertEquals(0, message.getInt32FieldCount11()); - assertEquals(1, message.getEnumFieldCount12().getNumber()); + assertEquals(0, message.getEnumFieldCount12().getNumber()); assertEquals("", message.getStringFieldCount13()); assertEquals(ByteString.EMPTY, message.getBytesFieldCount14()); assertEquals(0, message.getMessageFieldCount15().getSerializedSize()); diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 152bdadc..82f9582f 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -73,7 +73,7 @@ public class TextFormatTest extends TestCase { private static String exoticText = "repeated_int32: -1\n" + "repeated_int32: -2147483648\n" + - "repeated_int64: -1\n" + + "repeated_int64: -1,\n" + "repeated_int64: -9223372036854775808\n" + "repeated_uint32: 4294967295\n" + "repeated_uint32: 2147483648\n" + @@ -101,7 +101,7 @@ public class TextFormatTest extends TestCase { private static String canonicalExoticText = exoticText.replace(": .", ": 0.").replace(": -.", ": -0.") // short-form double - .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16"); + .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16").replace(",", ""); private String messageSetText = "[protobuf_unittest.TestMessageSetExtension1] {\n" + @@ -119,6 +119,7 @@ public class TextFormatTest extends TestCase { " i: 456\n" + "}\n"; + private final TextFormat.Parser parserWithOverwriteForbidden = TextFormat.Parser.newBuilder() .setSingularOverwritePolicy( @@ -460,6 +461,7 @@ public class TextFormatTest extends TestCase { } } + private void assertParseErrorWithOverwriteForbidden(String error, String text) { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -553,10 +555,10 @@ public class TextFormatTest extends TestCase { public void testEscape() throws Exception { // Escape sequences. - assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"", - TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\""))); - assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"", - TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"")); + assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177", + TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177"))); + assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177", + TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177")); assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""), TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"")); assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"", @@ -900,6 +902,7 @@ public class TextFormatTest extends TestCase { .build())); } + public void testParseNonRepeatedFields() throws Exception { assertParseSuccessWithOverwriteForbidden( "repeated_int32: 1\n" + diff --git a/java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java new file mode 100644 index 00000000..8f45976f --- /dev/null +++ b/java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java @@ -0,0 +1,255 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.EnumDescriptor; +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; +import com.google.protobuf.TextFormat.ParseException; + +import junit.framework.TestCase; + +/** + * Unit tests for protos that keep unknown enum values rather than discard + * them as unknown fields. + */ +public class UnknownEnumValueTest extends TestCase { + public void testUnknownEnumValues() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalNestedEnumValue(4321); + builder.addRepeatedNestedEnumValue(5432); + builder.addPackedNestedEnumValue(6543); + TestAllTypes message = builder.build(); + assertEquals(4321, message.getOptionalNestedEnumValue()); + assertEquals(5432, message.getRepeatedNestedEnumValue(0)); + assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue()); + assertEquals(6543, message.getPackedNestedEnumValue(0)); + // Returns UNRECOGNIZED if an enum type is requested. + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum()); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0)); + + // Test serialization and parsing. + ByteString data = message.toByteString(); + message = TestAllTypes.parseFrom(data); + assertEquals(4321, message.getOptionalNestedEnumValue()); + assertEquals(5432, message.getRepeatedNestedEnumValue(0)); + assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue()); + assertEquals(6543, message.getPackedNestedEnumValue(0)); + // Returns UNRECOGNIZED if an enum type is requested. + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum()); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0)); + + // Test toBuilder(). + builder = message.toBuilder(); + assertEquals(4321, builder.getOptionalNestedEnumValue()); + assertEquals(5432, builder.getRepeatedNestedEnumValue(0)); + assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue()); + assertEquals(6543, builder.getPackedNestedEnumValue(0)); + // Returns UNRECOGNIZED if an enum type is requested. + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum()); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0)); + + // Test mergeFrom(). + builder = TestAllTypes.newBuilder().mergeFrom(message); + assertEquals(4321, builder.getOptionalNestedEnumValue()); + assertEquals(5432, builder.getRepeatedNestedEnumValue(0)); + assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue()); + assertEquals(6543, builder.getPackedNestedEnumValue(0)); + // Returns UNRECOGNIZED if an enum type is requested. + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum()); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0)); + assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0)); + + // Test equals() and hashCode() + TestAllTypes sameMessage = builder.build(); + assertEquals(message, sameMessage); + assertEquals(message.hashCode(), sameMessage.hashCode()); + + // Getting the numeric value of UNRECOGNIZED will throw an exception. + try { + TestAllTypes.NestedEnum.UNRECOGNIZED.getNumber(); + fail("Exception is expected."); + } catch (IllegalArgumentException e) { + // Expected. + } + + // Setting an enum field to an UNRECOGNIZED value will throw an exception. + try { + builder.setOptionalNestedEnum(builder.getOptionalNestedEnum()); + fail("Exception is expected."); + } catch (IllegalArgumentException e) { + // Expected. + } + try { + builder.addRepeatedNestedEnum(builder.getOptionalNestedEnum()); + fail("Exception is expected."); + } catch (IllegalArgumentException e) { + // Expected. + } + } + + public void testUnknownEnumValueInReflectionApi() throws Exception { + Descriptor descriptor = TestAllTypes.getDescriptor(); + FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); + FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum"); + FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum"); + EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); + + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setField(optionalNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(4321)); + builder.addRepeatedField(repeatedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(5432)); + builder.addRepeatedField(packedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(6543)); + TestAllTypes message = builder.build(); + + // Getters will return unknown enum values as EnumValueDescriptor. + EnumValueDescriptor unknown4321 = + (EnumValueDescriptor) message.getField(optionalNestedEnumField); + EnumValueDescriptor unknown5432 = + (EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0); + EnumValueDescriptor unknown6543 = + (EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0); + assertEquals(4321, unknown4321.getNumber()); + assertEquals(5432, unknown5432.getNumber()); + assertEquals(6543, unknown6543.getNumber()); + + // Unknown EnumValueDescriptor will map to UNRECOGNIZED. + assertEquals( + TestAllTypes.NestedEnum.valueOf(unknown4321), + TestAllTypes.NestedEnum.UNRECOGNIZED); + assertEquals( + TestAllTypes.NestedEnum.valueOf(unknown5432), + TestAllTypes.NestedEnum.UNRECOGNIZED); + assertEquals( + TestAllTypes.NestedEnum.valueOf(unknown6543), + TestAllTypes.NestedEnum.UNRECOGNIZED); + + // Setters also accept unknown EnumValueDescriptor. + builder.setField(optionalNestedEnumField, unknown6543); + builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321); + builder.setRepeatedField(packedNestedEnumField, 0, unknown5432); + message = builder.build(); + // Like other descriptors, unknown EnumValueDescriptor can be compared by + // object identity. + assertTrue(unknown6543 == message.getField(optionalNestedEnumField)); + assertTrue(unknown4321 == message.getRepeatedField(repeatedNestedEnumField, 0)); + assertTrue(unknown5432 == message.getRepeatedField(packedNestedEnumField, 0)); + } + + public void testUnknownEnumValueWithDynamicMessage() throws Exception { + Descriptor descriptor = TestAllTypes.getDescriptor(); + FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); + FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum"); + FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum"); + EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); + + Message dynamicMessageDefaultInstance = DynamicMessage.getDefaultInstance(descriptor); + + Message.Builder builder = dynamicMessageDefaultInstance.newBuilderForType(); + builder.setField(optionalNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(4321)); + builder.addRepeatedField(repeatedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(5432)); + builder.addRepeatedField(packedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(6543)); + Message message = builder.build(); + assertEquals(4321, + ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber()); + assertEquals(5432, + ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber()); + assertEquals(6543, + ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber()); + + // Test reflection based serialization/parsing implementation. + ByteString data = message.toByteString(); + message = dynamicMessageDefaultInstance + .newBuilderForType() + .mergeFrom(data) + .build(); + assertEquals(4321, + ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber()); + assertEquals(5432, + ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber()); + assertEquals(6543, + ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber()); + + // Test reflection based equals()/hashCode(). + builder = dynamicMessageDefaultInstance.newBuilderForType(); + builder.setField(optionalNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(4321)); + builder.addRepeatedField(repeatedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(5432)); + builder.addRepeatedField(packedNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(6543)); + Message sameMessage = builder.build(); + assertEquals(message, sameMessage); + assertEquals(message.hashCode(), sameMessage.hashCode()); + builder.setField(optionalNestedEnumField, + enumType.findValueByNumberCreatingIfUnknown(0)); + Message differentMessage = builder.build(); + assertFalse(message.equals(differentMessage)); + } + + public void testUnknownEnumValuesInTextFormat() { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.setOptionalNestedEnumValue(4321); + builder.addRepeatedNestedEnumValue(5432); + builder.addPackedNestedEnumValue(6543); + TestAllTypes message = builder.build(); + + // We can print a message with unknown enum values. + String textData = TextFormat.printToString(message); + assertEquals( + "optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n" + + "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n" + + "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n", textData); + + // Parsing unknown enum values will fail just like parsing other kinds of + // unknown fields. + try { + TextFormat.merge(textData, builder); + fail(); + } catch (ParseException e) { + // expected. + } + } +} diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java new file mode 100644 index 00000000..6372b7a7 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java @@ -0,0 +1,317 @@ +// 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. + +package com.google.protobuf; + +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * Tests for {@link UnknownFieldSetLite}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class UnknownFieldSetLiteTest extends TestCase { + + public void testNoDataIsDefaultInstance() { + assertSame( + UnknownFieldSetLite.getDefaultInstance(), + UnknownFieldSetLite.newBuilder() + .build()); + } + + public void testDefaultInstance() { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); + + assertEquals(0, unknownFields.getSerializedSize()); + assertEquals(ByteString.EMPTY, toByteString(unknownFields)); + } + + public void testMergeFieldFrom() throws IOException { + Foo foo = Foo.newBuilder() + .setValue(2) + .build(); + + CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); + + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeFieldFrom(input.readTag(), input); + + assertEquals(foo.toByteString(), toByteString(builder.build())); + } + + public void testSerializedSize() throws IOException { + Foo foo = Foo.newBuilder() + .setValue(2) + .build(); + + CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); + + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeFieldFrom(input.readTag(), input); + + assertEquals(foo.toByteString().size(), builder.build().getSerializedSize()); + } + + public void testMergeVarintField() throws IOException { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeVarintField(10, 2); + + CodedInputStream input = + CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); + + int tag = input.readTag(); + assertEquals(10, WireFormat.getTagFieldNumber(tag)); + assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); + assertEquals(2, input.readUInt64()); + assertTrue(input.isAtEnd()); + } + + public void testMergeVarintField_negative() throws IOException { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeVarintField(10, -6); + + CodedInputStream input = + CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); + + int tag = input.readTag(); + assertEquals(10, WireFormat.getTagFieldNumber(tag)); + assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); + assertEquals(-6, input.readUInt64()); + assertTrue(input.isAtEnd()); + } + + public void testEqualsAndHashCode() { + UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder(); + builder1.mergeVarintField(10, 2); + UnknownFieldSetLite unknownFields1 = builder1.build(); + + UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder(); + builder2.mergeVarintField(10, 2); + UnknownFieldSetLite unknownFields2 = builder2.build(); + + assertEquals(unknownFields1, unknownFields2); + assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode()); + assertFalse(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance())); + assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode()); + } + + public void testConcat() throws IOException { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeVarintField(10, 2); + UnknownFieldSetLite unknownFields = builder.build(); + + unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields); + + CodedInputStream input = + CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); + + int tag = input.readTag(); + assertEquals(10, WireFormat.getTagFieldNumber(tag)); + assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); + assertEquals(2, input.readUInt64()); + assertFalse(input.isAtEnd()); + input.readTag(); + assertEquals(10, WireFormat.getTagFieldNumber(tag)); + assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); + assertEquals(2, input.readUInt64()); + assertTrue(input.isAtEnd()); + } + + public void testConcat_empty() { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat( + UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); + + assertEquals(0, unknownFields.getSerializedSize()); + assertEquals(ByteString.EMPTY, toByteString(unknownFields)); + } + + public void testBuilderReuse() throws IOException { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.mergeVarintField(10, 2); + builder.build(); + + try { + builder.build(); + fail(); + } catch (IllegalStateException e) { + // Expected. + } + + try { + builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0])); + fail(); + } catch (IllegalStateException e) { + // Expected. + } + + try { + builder.mergeVarintField(5, 1); + fail(); + } catch (IllegalStateException e) { + // Expected. + } + } + + public void testBuilderReuse_empty() { + UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); + builder.build(); + + try { + builder.build(); + fail(); + } catch (IllegalStateException e) { + // Expected. + } + } + + public void testRoundTrips() throws InvalidProtocolBufferException { + Foo foo = Foo.newBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder() + .setName("name") + .build()) + .setExtension(LiteEqualsAndHash.varint, 22) + .setExtension(LiteEqualsAndHash.fixed32, 44) + .setExtension(LiteEqualsAndHash.fixed64, 66L) + .setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder() + .setGroupValue("value") + .build()) + .build(); + + Foo copy = Foo.parseFrom(foo.toByteArray()); + + assertEquals(foo.getSerializedSize(), copy.getSerializedSize()); + assertFalse(foo.equals(copy)); + + Foo secondCopy = Foo.parseFrom(foo.toByteArray()); + assertEquals(copy, secondCopy); + + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + LiteEqualsAndHash.registerAllExtensions(extensionRegistry); + Foo copyOfCopy = Foo.parseFrom(copy.toByteArray(), extensionRegistry); + + assertEquals(foo, copyOfCopy); + } + + public void testMalformedBytes() { + try { + Foo.parseFrom("this is a malformed protocol buffer".getBytes(StandardCharsets.UTF_8)); + fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + public void testMissingStartGroupTag() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.writeTag(100, WireFormat.WIRETYPE_END_GROUP); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + public void testMissingEndGroupTag() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + public void testMismatchingGroupTags() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.writeTag(101, WireFormat.WIRETYPE_END_GROUP); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + public void testTruncatedInput() { + Foo foo = Foo.newBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder() + .setName("name") + .build()) + .setExtension(LiteEqualsAndHash.varint, 22) + .setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder() + .setGroupValue("value") + .build()) + .build(); + + try { + Foo.parseFrom(foo.toByteString().substring(0, foo.toByteString().size() - 10)); + fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + private ByteString toByteString(UnknownFieldSetLite unknownFields) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); + try { + unknownFields.writeTo(output); + output.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return ByteString.copyFrom(byteArrayOutputStream.toByteArray()); + } +} diff --git a/java/src/test/java/com/google/protobuf/field_presence_test.proto b/java/src/test/java/com/google/protobuf/field_presence_test.proto new file mode 100644 index 00000000..8d8ea8ef --- /dev/null +++ b/java/src/test/java/com/google/protobuf/field_presence_test.proto @@ -0,0 +1,93 @@ +// 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. + +syntax = "proto3"; + +package field_presence_test; + +import "google/protobuf/unittest.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldPresenceTestProto"; +option java_generate_equals_and_hash = true; + +message TestAllTypes { + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + } + message NestedMessage { + optional int32 value = 1; + } + + optional int32 optional_int32 = 1; + optional string optional_string = 2; + optional bytes optional_bytes = 3; + optional NestedEnum optional_nested_enum = 4; + optional NestedMessage optional_nested_message = 5; + optional protobuf_unittest.TestRequired optional_proto2_message = 6; + + oneof oneof_field { + int32 oneof_int32 = 11; + uint32 oneof_uint32 = 12; + string oneof_string = 13; + bytes oneof_bytes = 14; + NestedEnum oneof_nested_enum = 15; + NestedMessage oneof_nested_message = 16; + protobuf_unittest.TestRequired oneof_proto2_message = 17; + } + + repeated int32 repeated_int32 = 21; + repeated string repeated_string = 22; + repeated bytes repeated_bytes = 23; + repeated NestedEnum repeated_nested_enum = 24; + repeated NestedMessage repeated_nested_message = 25; + repeated protobuf_unittest.TestRequired repeated_proto2_message = 26; + repeated NestedEnum packed_nested_enum = 27 [packed = true]; +} + +message TestOptionalFieldsOnly { + optional int32 optional_int32 = 1; + optional string optional_string = 2; + optional bytes optional_bytes = 3; + optional TestAllTypes.NestedEnum optional_nested_enum = 4; + optional TestAllTypes.NestedMessage optional_nested_message = 5; + optional protobuf_unittest.TestRequired optional_proto2_message = 6; +} + +message TestRepeatedFieldsOnly { + repeated int32 repeated_int32 = 21; + repeated string repeated_string = 22; + repeated bytes repeated_bytes = 23; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 24; + repeated TestAllTypes.NestedMessage repeated_nested_message = 25; + repeated protobuf_unittest.TestRequired repeated_proto2_message = 26; +} diff --git a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto index baed4e10..015dc267 100644 --- a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto +++ b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto @@ -32,6 +32,7 @@ // // A proto file with lazy fields +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto index 68615672..86837250 100644 --- a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto +++ b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto @@ -30,6 +30,7 @@ // Author: pbogle@google.com (Phil Bogle) +syntax = "proto2"; package protobuf_unittest.lite_equals_and_hash; @@ -41,9 +42,15 @@ option optimize_for = LITE_RUNTIME; message Foo { optional int32 value = 1; repeated Bar bar = 2; + + extensions 100 to max; } message Bar { + extend Foo { + optional Bar foo_ext = 100; + } + optional string name = 1; } @@ -53,3 +60,13 @@ message BarPrime { message Empty { } + +extend Foo { + optional int32 varint = 101; + optional fixed32 fixed32 = 102; + optional fixed64 fixed64 = 103; + optional group MyGroup = 104 { + optional string group_value = 1; + } +} + diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto b/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto new file mode 100644 index 00000000..4f23a4a8 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto @@ -0,0 +1,63 @@ +// 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. + +syntax = "proto2"; + + +option java_outer_classname = "MapForProto2TestProto"; +option java_generate_equals_and_hash = true; + +message TestMap { + message MessageValue { + optional int32 value = 1; + } + enum EnumValue { + FOO = 0; + BAR = 1; + BAZ = 2; + QUX = 3; + } + + map int32_to_int32_field = 1; + map int32_to_string_field = 2; + map int32_to_bytes_field = 3; + map int32_to_enum_field = 4; + map int32_to_message_field = 5; + map string_to_int32_field = 6; +} + +message TestUnknownEnumValue { + // Wire-compatible with TestMap.int32_to_enum_field so we can test the + // parsing behavior of TestMap regarding unknown enum values. + map int32_to_int32_field = 4; +} +package map_for_proto2_lite_test; +option java_package = "map_lite_test"; +option optimize_for = LITE_RUNTIME; diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto b/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto new file mode 100644 index 00000000..36dfbd10 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto @@ -0,0 +1,62 @@ +// 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. + +syntax = "proto2"; + +package map_for_proto2_test; + +option java_package = "map_test"; +option java_outer_classname = "MapForProto2TestProto"; +option java_generate_equals_and_hash = true; + +message TestMap { + message MessageValue { + optional int32 value = 1; + } + enum EnumValue { + FOO = 0; + BAR = 1; + BAZ = 2; + QUX = 3; + } + + map int32_to_int32_field = 1; + map int32_to_string_field = 2; + map int32_to_bytes_field = 3; + map int32_to_enum_field = 4; + map int32_to_message_field = 5; + map string_to_int32_field = 6; +} + +message TestUnknownEnumValue { + // Wire-compatible with TestMap.int32_to_enum_field so we can test the + // parsing behavior of TestMap regarding unknown enum values. + map int32_to_int32_field = 4; +} diff --git a/java/src/test/java/com/google/protobuf/map_test.proto b/java/src/test/java/com/google/protobuf/map_test.proto new file mode 100644 index 00000000..105ee3f8 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/map_test.proto @@ -0,0 +1,63 @@ +// 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. + +syntax = "proto3"; + +package map_test; + +option java_package = "map_test"; +option java_outer_classname = "MapTestProto"; +option java_generate_equals_and_hash = true; + +message TestMap { + message MessageValue { + optional int32 value = 1; + } + enum EnumValue { + FOO = 0; + BAR = 1; + BAZ = 2; + QUX = 3; + } + + map int32_to_int32_field = 1; + map int32_to_string_field = 2; + map int32_to_bytes_field = 3; + map int32_to_enum_field = 4; + map int32_to_message_field = 5; + map string_to_int32_field = 6; +} + +// Used to test that a nested bulider containing map fields will properly +// propagate the onChange event and mark its parent dirty when a change +// is made to a map field. +message TestOnChangeEventPropagation { + optional TestMap optional_message = 1; +} diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/src/test/java/com/google/protobuf/multiple_files_test.proto index 7ec89a05..92790506 100644 --- a/java/src/test/java/com/google/protobuf/multiple_files_test.proto +++ b/java/src/test/java/com/google/protobuf/multiple_files_test.proto @@ -32,6 +32,7 @@ // // A proto file which tests the java_multiple_files option. +syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default diff --git a/java/src/test/java/com/google/protobuf/nested_builders_test.proto b/java/src/test/java/com/google/protobuf/nested_builders_test.proto index 8ab4a433..a5dd66d8 100644 --- a/java/src/test/java/com/google/protobuf/nested_builders_test.proto +++ b/java/src/test/java/com/google/protobuf/nested_builders_test.proto @@ -30,6 +30,7 @@ // Author: jonp@google.com (Jon Perlow) // +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/nested_extension.proto b/java/src/test/java/com/google/protobuf/nested_extension.proto index 86492867..704e649e 100644 --- a/java/src/test/java/com/google/protobuf/nested_extension.proto +++ b/java/src/test/java/com/google/protobuf/nested_extension.proto @@ -33,6 +33,7 @@ // A proto file with nested extensions. Note that this must be defined in // a separate file to properly test the initialization of the outer class. +syntax = "proto2"; import "com/google/protobuf/non_nested_extension.proto"; diff --git a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto b/java/src/test/java/com/google/protobuf/nested_extension_lite.proto index 9c686829..a95c38b2 100644 --- a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto +++ b/java/src/test/java/com/google/protobuf/nested_extension_lite.proto @@ -34,6 +34,7 @@ // this must be defined in a separate file to properly test the initialization // of the outer class. +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension.proto b/java/src/test/java/com/google/protobuf/non_nested_extension.proto index cb2f8b00..31fac552 100644 --- a/java/src/test/java/com/google/protobuf/non_nested_extension.proto +++ b/java/src/test/java/com/google/protobuf/non_nested_extension.proto @@ -32,6 +32,7 @@ // // A proto file with extensions. +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto b/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto index c1f744b8..37c369ed 100644 --- a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto +++ b/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto @@ -32,6 +32,7 @@ // // A proto file with extensions for a MessageLite messages. +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto index c5114f89..42083681 100644 --- a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto index 741cd281..3e5956b0 100644 --- a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto index 5d5d4ac9..74a8ba3c 100644 --- a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto index 202e8c91..67035fd5 100644 --- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto +++ b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto @@ -33,6 +33,7 @@ // This file tests that various identifiers work as field and type names even // though the same identifiers are used internally by the java code generator. +syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default @@ -59,12 +60,14 @@ message Descriptor { } optional NestedDescriptor nested_descriptor = 2; enum NestedEnum { + UNKNOWN = 0; FOO = 1; } } message Parser { enum ParserEnum { + UNKNOWN = 0; PARSER = 1; } optional ParserEnum parser = 1; @@ -72,6 +75,7 @@ message Parser { message Deprecated { enum TestEnum { + UNKNOWN = 0; FOO = 1; // Test if @Deprecated annotation conflicts with Deprecated message name. @@ -118,6 +122,7 @@ service TestConflictingMethodNames { message TestConflictingFieldNames { enum TestEnum { + UNKNOWN = 0; FOO = 1; } message TestMessage { @@ -142,16 +147,23 @@ message TestConflictingFieldNames { // This field conflicts with "int32_field" as they both generate // the method getInt32FieldList(). - required int32 int32_field_list = 31; + required int32 int32_field_list = 31; // NO_PROTO3 - extensions 1000 to max; + extensions 1000 to max; // NO_PROTO3 repeated int64 int64_field = 41; - extend TestConflictingFieldNames { + extend TestConflictingFieldNames { // NO_PROTO3 // We don't generate accessors for extensions so the following extension // fields don't conflict with the repeated field "int64_field". - optional int64 int64_field_count = 1001; - optional int64 int64_field_list = 1002; - } + optional int64 int64_field_count = 1001; // NO_PROTO3 + optional int64 int64_field_list = 1002; // NO_PROTO3 + } // NO_PROTO3 } +message TestMapField { + message MapField {} + message Pair {} + message Message {} + + map map_field = 1; +} diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8.proto b/java/src/test/java/com/google/protobuf/test_check_utf8.proto index 206946d8..119c1dcb 100644 --- a/java/src/test/java/com/google/protobuf/test_check_utf8.proto +++ b/java/src/test/java/com/google/protobuf/test_check_utf8.proto @@ -31,6 +31,7 @@ // Author: Jacob Butcher (jbaum@google.com) // // Test file option java_string_check_utf8. +syntax = "proto2"; package proto2_test_check_utf8; diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto index fa057a88..f06d76d6 100644 --- a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto +++ b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto @@ -31,6 +31,7 @@ // Author: Jacob Butcher (jbaum@google.com) // // Test file option java_string_check_utf8. +syntax = "proto2"; package proto2_test_check_utf8_size; diff --git a/java/src/test/java/com/google/protobuf/test_custom_options.proto b/java/src/test/java/com/google/protobuf/test_custom_options.proto index f6a5ecd4..f8efd455 100644 --- a/java/src/test/java/com/google/protobuf/test_custom_options.proto +++ b/java/src/test/java/com/google/protobuf/test_custom_options.proto @@ -32,6 +32,7 @@ // // Test that custom options defined in a proto file's dependencies are properly // initialized. +syntax = "proto2"; package protobuf_unittest; diff --git a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto b/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto index 72e05a36..645f57b4 100644 --- a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto +++ b/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto @@ -29,6 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: Darick Tong (darick@google.com) +syntax = "proto2"; package protobuf_unittest; diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py index 6da8bb0b..af571b7c 100755 --- a/python/google/protobuf/descriptor.py +++ b/python/google/protobuf/descriptor.py @@ -841,9 +841,10 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True): field_proto.number, field_proto.type, FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type), field_proto.label, None, nested_desc, enum_desc, None, False, None, - has_default_value=False) + options=field_proto.options, has_default_value=False) fields.append(field) desc_name = '.'.join(full_message_name) return Descriptor(desc_proto.name, desc_name, None, None, fields, - nested_types.values(), enum_types.values(), []) + nested_types.values(), enum_types.values(), [], + options=desc_proto.options) diff --git a/python/google/protobuf/descriptor_database.py b/python/google/protobuf/descriptor_database.py index 55fb8c70..b10021e9 100644 --- a/python/google/protobuf/descriptor_database.py +++ b/python/google/protobuf/descriptor_database.py @@ -133,5 +133,5 @@ def _ExtractSymbols(desc_proto, package): for nested_type in desc_proto.nested_type: for symbol in _ExtractSymbols(nested_type, message_name): yield symbol - for enum_type in desc_proto.enum_type: - yield '.'.join((message_name, enum_type.name)) + for enum_type in desc_proto.enum_type: + yield '.'.join((message_name, enum_type.name)) diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py index cf234cfa..bcac513a 100644 --- a/python/google/protobuf/descriptor_pool.py +++ b/python/google/protobuf/descriptor_pool.py @@ -554,7 +554,7 @@ class DescriptorPool(object): field_desc.default_value = field_proto.default_value.lower() == 'true' elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: field_desc.default_value = field_desc.enum_type.values_by_name[ - field_proto.default_value].index + field_proto.default_value].number elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: field_desc.default_value = text_encoding.CUnescape( field_proto.default_value) diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py index fc65b69a..8970f5c2 100644 --- a/python/google/protobuf/internal/descriptor_database_test.py +++ b/python/google/protobuf/internal/descriptor_database_test.py @@ -58,6 +58,8 @@ class DescriptorDatabaseTest(basetest.TestCase): 'google.protobuf.python.internal.Factory2Enum')) self.assertEquals(file_desc_proto, db.FindFileContainingSymbol( 'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum')) + self.assertEquals(file_desc_proto, db.FindFileContainingSymbol( + 'google.protobuf.python.internal.MessageWithNestedEnumOnly.NestedEnum')) if __name__ == '__main__': basetest.main() diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index d2f85579..11ef61c5 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -48,6 +48,7 @@ from google.protobuf.internal import factory_test2_pb2 from google.protobuf import descriptor from google.protobuf import descriptor_database from google.protobuf import descriptor_pool +from google.protobuf import symbol_database class DescriptorPoolTest(basetest.TestCase): @@ -237,6 +238,32 @@ class DescriptorPoolTest(basetest.TestCase): TEST2_FILE.CheckFile(self, self.pool) + def testEnumDefaultValue(self): + """Test the default value of enums which don't start at zero.""" + def _CheckDefaultValue(file_descriptor): + default_value = (file_descriptor + .message_types_by_name['DescriptorPoolTest1'] + .fields_by_name['nested_enum'] + .default_value) + self.assertEqual(default_value, + descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA) + # First check what the generated descriptor contains. + _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR) + # Then check the generated pool. Normally this is the same descriptor. + file_descriptor = symbol_database.Default().pool.FindFileByName( + 'google/protobuf/internal/descriptor_pool_test1.proto') + self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR) + _CheckDefaultValue(file_descriptor) + + # Then check the dynamic pool and its internal DescriptorDatabase. + descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString( + descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb) + self.pool.Add(descriptor_proto) + # And do the same check as above + file_descriptor = self.pool.FindFileByName( + 'google/protobuf/internal/descriptor_pool_test1.proto') + _CheckDefaultValue(file_descriptor) + class ProtoFile(object): @@ -328,7 +355,7 @@ class EnumField(object): test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM, field_desc.cpp_type) test.assertTrue(field_desc.has_default_value) - test.assertEqual(enum_desc.values_by_name[self.default_value].index, + test.assertEqual(enum_desc.values_by_name[self.default_value].number, field_desc.default_value) test.assertEqual(msg_desc, field_desc.containing_type) test.assertEqual(enum_desc, field_desc.enum_type) diff --git a/python/google/protobuf/internal/descriptor_pool_test1.proto b/python/google/protobuf/internal/descriptor_pool_test1.proto index 6dfe4ef3..00816b78 100644 --- a/python/google/protobuf/internal/descriptor_pool_test1.proto +++ b/python/google/protobuf/internal/descriptor_pool_test1.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package google.protobuf.python.internal; diff --git a/python/google/protobuf/internal/descriptor_pool_test2.proto b/python/google/protobuf/internal/descriptor_pool_test2.proto index fbc84382..e3fa660c 100644 --- a/python/google/protobuf/internal/descriptor_pool_test2.proto +++ b/python/google/protobuf/internal/descriptor_pool_test2.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package google.protobuf.python.internal; import "google/protobuf/internal/descriptor_pool_test1.proto"; diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index b3777e39..3924f21a 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -665,5 +665,15 @@ class MakeDescriptorTest(basetest.TestCase): descriptor.FieldDescriptor.CPPTYPE_UINT64) + def testMakeDescriptorWithOptions(self): + descriptor_proto = descriptor_pb2.DescriptorProto() + aggregate_message = unittest_custom_options_pb2.AggregateMessage + aggregate_message.DESCRIPTOR.CopyToProto(descriptor_proto) + reformed_descriptor = descriptor.MakeDescriptor(descriptor_proto) + + options = reformed_descriptor.GetOptions() + self.assertEquals(101, + options.Extensions[unittest_custom_options_pb2.msgopt].i) + if __name__ == '__main__': basetest.main() diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto index 9f5a3919..d2fbbeec 100644 --- a/python/google/protobuf/internal/factory_test1.proto +++ b/python/google/protobuf/internal/factory_test1.proto @@ -30,6 +30,7 @@ // Author: matthewtoia@google.com (Matt Toia) +syntax = "proto2"; package google.protobuf.python.internal; diff --git a/python/google/protobuf/internal/factory_test2.proto b/python/google/protobuf/internal/factory_test2.proto index 27feb6ce..bb1b54ad 100644 --- a/python/google/protobuf/internal/factory_test2.proto +++ b/python/google/protobuf/internal/factory_test2.proto @@ -30,6 +30,7 @@ // Author: matthewtoia@google.com (Matt Toia) +syntax = "proto2"; package google.protobuf.python.internal; @@ -87,6 +88,12 @@ message LoopMessage { optional Factory2Message loop = 1; } +message MessageWithNestedEnumOnly { + enum NestedEnum { + NESTED_MESSAGE_ENUM_0 = 0; + } +} + extend Factory1Message { optional string another_field = 1002; } diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 422fa9a6..14b05cca 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -35,7 +35,7 @@ # indirect testing of the protocol compiler output. """Unittest that directly tests the output of the pure-Python protocol -compiler. See //google/protobuf/reflection_test.py for a test which +compiler. See //google/protobuf/internal/reflection_test.py for a test which further ensures that we can use Python protocol message objects as we expect. """ @@ -281,6 +281,8 @@ class GeneratorTest(basetest.TestCase): "baz") self.assertEqual(message.Extensions[test_bad_identifiers_pb2.service], "qux") + self.assertEqual(message.Extensions[test_bad_identifiers_pb2.class_], + "Foo") def testOneof(self): desc = unittest_pb2.TestAllTypes.DESCRIPTOR diff --git a/python/google/protobuf/internal/import_test_package/BUILD b/python/google/protobuf/internal/import_test_package/BUILD new file mode 100644 index 00000000..90e59505 --- /dev/null +++ b/python/google/protobuf/internal/import_test_package/BUILD @@ -0,0 +1,27 @@ +# Description: +# An example package that contains nested protos that are imported from +# __init__.py. See testPackageInitializationImport in reflection_test.py for +# details. + +package( + default_visibility = ["//net/proto2/python/internal:__pkg__"], +) + +proto_library( + name = "inner_proto", + srcs = ["inner.proto"], + py_api_version = 2, +) + +proto_library( + name = "outer_proto", + srcs = ["outer.proto"], + py_api_version = 2, + deps = [":inner_proto"], +) + +py_library( + name = "import_test_package", + srcs = ["__init__.py"], + deps = [":outer_proto"], +) diff --git a/python/google/protobuf/internal/import_test_package/__init__.py b/python/google/protobuf/internal/import_test_package/__init__.py new file mode 100644 index 00000000..5121dd0e --- /dev/null +++ b/python/google/protobuf/internal/import_test_package/__init__.py @@ -0,0 +1,33 @@ +# 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. + +"""Sample module importing a nested proto from itself.""" + +from google.protobuf.internal.import_test_package import outer_pb2 as myproto diff --git a/python/google/protobuf/internal/import_test_package/inner.proto b/python/google/protobuf/internal/import_test_package/inner.proto new file mode 100644 index 00000000..2887c123 --- /dev/null +++ b/python/google/protobuf/internal/import_test_package/inner.proto @@ -0,0 +1,37 @@ +// 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. + +syntax = "proto2"; + +package google.protobuf.python.internal.import_test_package; + +message Inner { + optional int32 value = 1 [default = 57]; +} diff --git a/python/google/protobuf/internal/import_test_package/outer.proto b/python/google/protobuf/internal/import_test_package/outer.proto new file mode 100644 index 00000000..a27fb5c8 --- /dev/null +++ b/python/google/protobuf/internal/import_test_package/outer.proto @@ -0,0 +1,39 @@ +// 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. + +syntax = "proto2"; + +package google.protobuf.python.internal.import_test_package; + +import "google/protobuf/internal/import_test_package/inner.proto"; + +message Outer { + optional Inner inner = 1; +} diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 48b7ffd4..42e2ad7e 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -337,6 +337,20 @@ class MessageTest(basetest.TestCase): empty.ParseFromString(populated.SerializeToString()) self.assertEqual(str(empty), '') + def testRepeatedNestedFieldIteration(self): + msg = unittest_pb2.TestAllTypes() + msg.repeated_nested_message.add(bb=1) + msg.repeated_nested_message.add(bb=2) + msg.repeated_nested_message.add(bb=3) + msg.repeated_nested_message.add(bb=4) + + self.assertEquals([1, 2, 3, 4], + [m.bb for m in msg.repeated_nested_message]) + self.assertEquals([4, 3, 2, 1], + [m.bb for m in reversed(msg.repeated_nested_message)]) + self.assertEquals([4, 3, 2, 1], + [m.bb for m in msg.repeated_nested_message[::-1]]) + def testSortingRepeatedScalarFieldsDefaultComparator(self): """Check some different types with the default comparator.""" message = unittest_pb2.TestAllTypes() @@ -641,6 +655,32 @@ class MessageTest(basetest.TestCase): m2.ParseFromString(m.SerializeToString()) self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) + def testOneofCopyFrom(self): + m = unittest_pb2.TestAllTypes() + m.oneof_uint32 = 11 + m2 = unittest_pb2.TestAllTypes() + m2.CopyFrom(m) + self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) + + def testOneofNestedMergeFrom(self): + m = unittest_pb2.NestedTestAllTypes() + m.payload.oneof_uint32 = 11 + m2 = unittest_pb2.NestedTestAllTypes() + m2.payload.oneof_bytes = b'bb' + m2.child.payload.oneof_bytes = b'bb' + m2.MergeFrom(m) + self.assertEqual('oneof_uint32', m2.payload.WhichOneof('oneof_field')) + self.assertEqual('oneof_bytes', m2.child.payload.WhichOneof('oneof_field')) + + def testOneofClear(self): + m = unittest_pb2.TestAllTypes() + m.oneof_uint32 = 11 + m.Clear() + self.assertIsNone(m.WhichOneof('oneof_field')) + m.oneof_bytes = b'bb' + self.assertTrue(m.HasField('oneof_field')) + + def testSortEmptyRepeatedCompositeContainer(self): """Exercise a scenario that has led to segfaults in the past. """ diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto index e90f0cd3..161fc5e1 100644 --- a/python/google/protobuf/internal/missing_enum_values.proto +++ b/python/google/protobuf/internal/missing_enum_values.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + package google.protobuf.python.internal; message TestEnumValues { diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto index c04e597f..78f14673 100644 --- a/python/google/protobuf/internal/more_extensions.proto +++ b/python/google/protobuf/internal/more_extensions.proto @@ -30,6 +30,7 @@ // Author: robinson@google.com (Will Robinson) +syntax = "proto2"; package google.protobuf.internal; diff --git a/python/google/protobuf/internal/more_extensions_dynamic.proto b/python/google/protobuf/internal/more_extensions_dynamic.proto index 88bd9c1b..11f85ef6 100644 --- a/python/google/protobuf/internal/more_extensions_dynamic.proto +++ b/python/google/protobuf/internal/more_extensions_dynamic.proto @@ -34,6 +34,7 @@ // generated C++ type is available for the extendee, but the extension is // defined in a file whose C++ type is not in the binary. +syntax = "proto2"; import "google/protobuf/internal/more_extensions.proto"; diff --git a/python/google/protobuf/internal/more_messages.proto b/python/google/protobuf/internal/more_messages.proto index 61db66c5..2c6ab9ef 100644 --- a/python/google/protobuf/internal/more_messages.proto +++ b/python/google/protobuf/internal/more_messages.proto @@ -30,6 +30,7 @@ // Author: robinson@google.com (Will Robinson) +syntax = "proto2"; package google.protobuf.internal; diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py new file mode 100644 index 00000000..c74db7e7 --- /dev/null +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -0,0 +1,77 @@ +#! /usr/bin/python +# +# 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. + +"""Tests for google.protobuf.proto_builder.""" + +from google.apputils import basetest + +from google.protobuf import descriptor_pb2 +from google.protobuf import descriptor_pool +from google.protobuf import proto_builder +from google.protobuf import text_format + + +class ProtoBuilderTest(basetest.TestCase): + + def setUp(self): + self._fields = { + 'foo': descriptor_pb2.FieldDescriptorProto.TYPE_INT64, + 'bar': descriptor_pb2.FieldDescriptorProto.TYPE_STRING, + } + + def testMakeSimpleProtoClass(self): + """Test that we can create a proto class.""" + proto_cls = proto_builder.MakeSimpleProtoClass( + self._fields, + full_name='net.proto2.python.public.proto_builder_test.Test') + proto = proto_cls() + proto.foo = 12345 + proto.bar = 'asdf' + self.assertMultiLineEqual( + 'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto)) + + def testMakeSameProtoClassTwice(self): + """Test that the DescriptorPool is used.""" + pool = descriptor_pool.DescriptorPool() + proto_cls1 = proto_builder.MakeSimpleProtoClass( + self._fields, + full_name='net.proto2.python.public.proto_builder_test.Test', + pool=pool) + proto_cls2 = proto_builder.MakeSimpleProtoClass( + self._fields, + full_name='net.proto2.python.public.proto_builder_test.Test', + pool=pool) + self.assertIs(proto_cls1.DESCRIPTOR, proto_cls2.DESCRIPTOR) + + +if __name__ == '__main__': + basetest.main() diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py index a5c26f45..6fda6ae0 100755 --- a/python/google/protobuf/internal/python_message.py +++ b/python/google/protobuf/internal/python_message.py @@ -306,6 +306,17 @@ def _DefaultValueConstructorForField(field): return MakeScalarDefault +def _ReraiseTypeErrorWithFieldName(message_name, field_name): + """Re-raise the currently-handled TypeError with the field name added.""" + exc = sys.exc_info()[1] + if len(exc.args) == 1 and type(exc) is TypeError: + # simple TypeError; add field name to exception message + exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name)) + + # re-raise possibly-amended exception with original traceback: + raise type(exc), exc, sys.exc_info()[2] + + def _AddInitMethod(message_descriptor, cls): """Adds an __init__ method to cls.""" fields = message_descriptor.fields @@ -338,10 +349,16 @@ def _AddInitMethod(message_descriptor, cls): self._fields[field] = copy elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: copy = field._default_constructor(self) - copy.MergeFrom(field_value) + try: + copy.MergeFrom(field_value) + except TypeError: + _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) self._fields[field] = copy else: - setattr(self, field_name, field_value) + try: + setattr(self, field_name, field_value) + except TypeError: + _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) init.__module__ = None init.__doc__ = None @@ -691,6 +708,7 @@ def _AddClearMethod(message_descriptor, cls): # Clear fields. self._fields = {} self._unknown_fields = () + self._oneofs = {} self._Modified() cls.Clear = Clear @@ -993,6 +1011,8 @@ def _AddMergeFromMethod(cls): field_value.MergeFrom(value) else: self._fields[field] = value + if field.containing_oneof: + self._UpdateOneofState(field) if msg._unknown_fields: if not self._unknown_fields: diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index d59815d0..6b24b092 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -35,8 +35,6 @@ pure-Python protocol compiler. """ -__author__ = 'robinson@google.com (Will Robinson)' - import copy import gc import operator @@ -1252,15 +1250,18 @@ class ReflectionTest(basetest.TestCase): # Try something that *is* an extension handle, just not for # this message... - unknown_handle = more_extensions_pb2.optional_int_extension - self.assertRaises(KeyError, extendee_proto.HasExtension, - unknown_handle) - self.assertRaises(KeyError, extendee_proto.ClearExtension, - unknown_handle) - self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__, - unknown_handle) - self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__, - unknown_handle, 5) + for unknown_handle in (more_extensions_pb2.optional_int_extension, + more_extensions_pb2.optional_message_extension, + more_extensions_pb2.repeated_int_extension, + more_extensions_pb2.repeated_message_extension): + self.assertRaises(KeyError, extendee_proto.HasExtension, + unknown_handle) + self.assertRaises(KeyError, extendee_proto.ClearExtension, + unknown_handle) + self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__, + unknown_handle) + self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__, + unknown_handle, 5) # Try call HasExtension() with a valid handle, but for a # *repeated* field. (Just as with non-extension repeated @@ -1669,16 +1670,15 @@ class ReflectionTest(basetest.TestCase): proto.optional_string = str('Testing') self.assertEqual(proto.optional_string, unicode('Testing')) - # Try to assign a 'str' value which contains bytes that aren't 7-bit ASCII. + # Try to assign a 'bytes' object which contains non-UTF-8. self.assertRaises(ValueError, setattr, proto, 'optional_string', b'a\x80a') - if str is bytes: # PY2 - # Assign a 'str' object which contains a UTF-8 encoded string. - self.assertRaises(ValueError, - setattr, proto, 'optional_string', 'Тест') - else: - proto.optional_string = 'Тест' - # No exception thrown. + # No exception: Assign already encoded UTF-8 bytes to a string field. + utf8_bytes = u'Тест'.encode('utf-8') + proto.optional_string = utf8_bytes + # No exception: Assign the a non-ascii unicode object. + proto.optional_string = u'Тест' + # No exception thrown (normal str assignment containing ASCII). proto.optional_string = 'abc' def testStringUTF8Serialization(self): @@ -1774,6 +1774,24 @@ class ReflectionTest(basetest.TestCase): proto.optionalgroup.SetInParent() self.assertTrue(proto.HasField('optionalgroup')) + def testPackageInitializationImport(self): + """Test that we can import nested messages from their __init__.py. + + Such setup is not trivial since at the time of processing of __init__.py one + can't refer to its submodules by name in code, so expressions like + google.protobuf.internal.import_test_package.inner_pb2 + don't work. They do work in imports, so we have assign an alias at import + and then use that alias in generated code. + """ + # We import here since it's the import that used to fail, and we want + # the failure to have the right context. + # pylint: disable=g-import-not-at-top + from google.protobuf.internal import import_test_package + # pylint: enable=g-import-not-at-top + msg = import_test_package.myproto.Outer() + # Just check the default value. + self.assertEqual(57, msg.inner.value) + # Since we had so many tests for protocol buffer equality, we broke these out # into separate TestCase classes. @@ -2802,6 +2820,9 @@ class OptionsTest(basetest.TestCase): class ClassAPITest(basetest.TestCase): + @basetest.unittest.skipIf( + api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, + 'C++ implementation requires a call to MakeDescriptor()') def testMakeClassWithNestedDescriptor(self): leaf_desc = descriptor.Descriptor('leaf', 'package.parent.child.leaf', '', containing_type=None, fields=[], diff --git a/python/google/protobuf/internal/test_bad_identifiers.proto b/python/google/protobuf/internal/test_bad_identifiers.proto index 9eb18cb0..29fa38a2 100644 --- a/python/google/protobuf/internal/test_bad_identifiers.proto +++ b/python/google/protobuf/internal/test_bad_identifiers.proto @@ -30,6 +30,7 @@ // Author: kenton@google.com (Kenton Varda) +syntax = "proto2"; package protobuf_unittest; @@ -39,13 +40,15 @@ message TestBadIdentifiers { extensions 100 to max; } -// Make sure these reasonable extension names don't conflict with internal -// variables. extend TestBadIdentifiers { + // Make sure these reasonable extension names don't conflict with internal + // variables. optional string message = 100 [default="foo"]; optional string descriptor = 101 [default="bar"]; optional string reflection = 102 [default="baz"]; optional string service = 103 [default="qux"]; + // And Python keywords. + optional string class = 104 [default="Foo"]; } message AnotherMessage {} diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index b0a3a5f7..55e3c2c8 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -69,13 +69,18 @@ class TextFormatTest(basetest.TestCase): message.my_string = '115' message.my_int = 101 message.my_float = 111 + message.optional_nested_message.oo = 0 + message.optional_nested_message.bb = 1 self.CompareToGoldenText( self.RemoveRedundantZeros(text_format.MessageToString( message, use_index_order=True)), - 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n') + 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n' + 'optional_nested_message {\n oo: 0\n bb: 1\n}\n') self.CompareToGoldenText( self.RemoveRedundantZeros(text_format.MessageToString( - message)), 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n') + message)), + 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n' + 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') def testPrintAllExtensions(self): message = unittest_pb2.TestAllExtensions() @@ -511,7 +516,7 @@ class TextFormatTest(basetest.TestCase): message.repeated_string[4]) self.assertEqual(SLASH + 'x20', message.repeated_string[5]) - def testMergeRepeatedScalars(self): + def testMergeDuplicateScalars(self): message = unittest_pb2.TestAllTypes() text = ('optional_int32: 42 ' 'optional_int32: 67') @@ -519,7 +524,7 @@ class TextFormatTest(basetest.TestCase): self.assertIs(r, message) self.assertEqual(67, message.optional_int32) - def testParseRepeatedScalars(self): + def testParseDuplicateScalars(self): message = unittest_pb2.TestAllTypes() text = ('optional_int32: 42 ' 'optional_int32: 67') @@ -529,7 +534,7 @@ class TextFormatTest(basetest.TestCase): 'have multiple "optional_int32" fields.'), text_format.Parse, text, message) - def testMergeRepeatedNestedMessageScalars(self): + def testMergeDuplicateNestedMessageScalars(self): message = unittest_pb2.TestAllTypes() text = ('optional_nested_message { bb: 1 } ' 'optional_nested_message { bb: 2 }') @@ -537,7 +542,7 @@ class TextFormatTest(basetest.TestCase): self.assertTrue(r is message) self.assertEqual(2, message.optional_nested_message.bb) - def testParseRepeatedNestedMessageScalars(self): + def testParseDuplicateNestedMessageScalars(self): message = unittest_pb2.TestAllTypes() text = ('optional_nested_message { bb: 1 } ' 'optional_nested_message { bb: 2 }') @@ -547,7 +552,7 @@ class TextFormatTest(basetest.TestCase): 'should not have multiple "bb" fields.'), text_format.Parse, text, message) - def testMergeRepeatedExtensionScalars(self): + def testMergeDuplicateExtensionScalars(self): message = unittest_pb2.TestAllExtensions() text = ('[protobuf_unittest.optional_int32_extension]: 42 ' '[protobuf_unittest.optional_int32_extension]: 67') @@ -556,7 +561,7 @@ class TextFormatTest(basetest.TestCase): 67, message.Extensions[unittest_pb2.optional_int32_extension]) - def testParseRepeatedExtensionScalars(self): + def testParseDuplicateExtensionScalars(self): message = unittest_pb2.TestAllExtensions() text = ('[protobuf_unittest.optional_int32_extension]: 42 ' '[protobuf_unittest.optional_int32_extension]: 67') diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py index 56d26460..118725da 100755 --- a/python/google/protobuf/internal/type_checkers.py +++ b/python/google/protobuf/internal/type_checkers.py @@ -154,14 +154,13 @@ class UnicodeValueChecker(object): (proposed_value, type(proposed_value), (bytes, unicode))) raise TypeError(message) - # If the value is of type 'bytes' make sure that it is in 7-bit ASCII - # encoding. + # If the value is of type 'bytes' make sure that it is valid UTF-8 data. if isinstance(proposed_value, bytes): try: - proposed_value = proposed_value.decode('ascii') + proposed_value = proposed_value.decode('utf-8') except UnicodeDecodeError: - raise ValueError('%.1024r has type bytes, but isn\'t in 7-bit ASCII ' - 'encoding. Non-ASCII strings must be converted to ' + raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 ' + 'encoding. Non-UTF-8 strings must be converted to ' 'unicode objects before being added.' % (proposed_value)) return proposed_value diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 71775609..a4dc1f7c 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -38,12 +38,16 @@ __author__ = 'bohdank@google.com (Bohdan Koval)' from google.apputils import basetest from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 +from google.protobuf.internal import api_implementation from google.protobuf.internal import encoder from google.protobuf.internal import missing_enum_values_pb2 from google.protobuf.internal import test_util from google.protobuf.internal import type_checkers +@basetest.unittest.skipIf( + api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, + 'C++ implementation does not expose unknown fields to Python') class UnknownFieldsTest(basetest.TestCase): def setUp(self): @@ -175,7 +179,10 @@ class UnknownFieldsTest(basetest.TestCase): self.assertNotEqual(self.empty_message, message) -class UnknownFieldsTest(basetest.TestCase): +@basetest.unittest.skipIf( + api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, + 'C++ implementation does not expose unknown fields to Python') +class UnknownEnumValuesTest(basetest.TestCase): def setUp(self): self.descriptor = missing_enum_values_pb2.TestEnumValues.DESCRIPTOR diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py index c186452a..88ed9f4c 100755 --- a/python/google/protobuf/message.py +++ b/python/google/protobuf/message.py @@ -233,12 +233,21 @@ class Message(object): raise NotImplementedError def HasField(self, field_name): - """Checks if a certain field is set for the message. Note if the - field_name is not defined in the message descriptor, ValueError will be - raised.""" + """Checks if a certain field is set for the message, or if any field inside + a oneof group is set. Note that if the field_name is not defined in the + message descriptor, ValueError will be raised.""" raise NotImplementedError def ClearField(self, field_name): + """Clears the contents of a given field, or the field set inside a oneof + group. If the name neither refers to a defined field or oneof group, + ValueError is raised.""" + raise NotImplementedError + + def WhichOneof(self, oneof_group): + """Returns the name of the field that is set inside a oneof group, or + None if no field is set. If no group with the given name exists, ValueError + will be raised.""" raise NotImplementedError def HasExtension(self, extension_handle): diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py new file mode 100644 index 00000000..1fa28f1a --- /dev/null +++ b/python/google/protobuf/proto_builder.py @@ -0,0 +1,98 @@ +# 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. + +"""Dynamic Protobuf class creator.""" + +import hashlib +import os + +from google.protobuf import descriptor_pb2 +from google.protobuf import message_factory + + +def _GetMessageFromFactory(factory, full_name): + """Get a proto class from the MessageFactory by name. + + Args: + factory: a MessageFactory instance. + full_name: str, the fully qualified name of the proto type. + Returns: + a class, for the type identified by full_name. + Raises: + KeyError, if the proto is not found in the factory's descriptor pool. + """ + proto_descriptor = factory.pool.FindMessageTypeByName(full_name) + proto_cls = factory.GetPrototype(proto_descriptor) + return proto_cls + + +def MakeSimpleProtoClass(fields, full_name, pool=None): + """Create a Protobuf class whose fields are basic types. + + Note: this doesn't validate field names! + + Args: + fields: dict of {name: field_type} mappings for each field in the proto. + full_name: str, the fully-qualified name of the proto type. + pool: optional DescriptorPool instance. + Returns: + a class, the new protobuf class with a FileDescriptor. + """ + factory = message_factory.MessageFactory(pool=pool) + try: + proto_cls = _GetMessageFromFactory(factory, full_name) + return proto_cls + except KeyError: + # The factory's DescriptorPool doesn't know about this class yet. + pass + + # Use a consistent file name that is unlikely to conflict with any imported + # proto files. + fields_hash = hashlib.sha1() + for f_name, f_type in sorted(fields.items()): + fields_hash.update(f_name.encode('utf8')) + fields_hash.update(str(f_type).encode('utf8')) + proto_file_name = fields_hash.hexdigest() + '.proto' + + package, name = full_name.rsplit('.', 1) + file_proto = descriptor_pb2.FileDescriptorProto() + file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name) + file_proto.package = package + desc_proto = file_proto.message_type.add() + desc_proto.name = name + for f_number, (f_name, f_type) in enumerate(sorted(fields.items()), 1): + field_proto = desc_proto.field.add() + field_proto.name = f_name + field_proto.number = f_number + field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL + field_proto.type = f_type + + factory.pool.Add(file_proto) + return _GetMessageFromFactory(factory, full_name) diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py index dcf34a02..037bb72c 100644 --- a/python/google/protobuf/pyext/cpp_message.py +++ b/python/google/protobuf/pyext/cpp_message.py @@ -53,9 +53,5 @@ def NewMessage(bases, message_descriptor, dictionary): def InitMessage(message_descriptor, cls): - """Constructs a new message instance (called before instance's __init__).""" - - def SubInit(self, **kwargs): - super(cls, self).__init__(message_descriptor, **kwargs) - cls.__init__ = SubInit + """Finalizes the creation of a message class.""" cls.AddDescriptors(message_descriptor) diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index 3f7be73c..55bb0b72 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -35,6 +35,7 @@ #include #include +#include #include #define C(str) const_cast(str) @@ -46,7 +47,7 @@ #error "Python 3.0 - 3.2 are not supported." #else #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob)) + (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) #endif #endif @@ -65,10 +66,80 @@ namespace python { static google::protobuf::DescriptorPool* g_descriptor_pool = NULL; +namespace cmessage_descriptor { + +static void Dealloc(CMessageDescriptor* self) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* GetFullName(CMessageDescriptor* self, void *closure) { + return PyString_FromStringAndSize( + self->descriptor->full_name().c_str(), + self->descriptor->full_name().size()); +} + +static PyObject* GetName(CMessageDescriptor *self, void *closure) { + return PyString_FromStringAndSize( + self->descriptor->name().c_str(), + self->descriptor->name().size()); +} + +static PyGetSetDef Getters[] = { + { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, + { C("name"), (getter)GetName, NULL, "Unqualified name", NULL}, + {NULL} +}; + +} // namespace cmessage_descriptor + +PyTypeObject CMessageDescriptor_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + C("google.protobuf.internal." + "_net_proto2___python." + "CMessageDescriptor"), // tp_name + sizeof(CMessageDescriptor), // tp_basicsize + 0, // tp_itemsize + (destructor)cmessage_descriptor::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + C("A Message Descriptor"), // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + cmessage_descriptor::Getters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + PyType_GenericAlloc, // tp_alloc + PyType_GenericNew, // tp_new + PyObject_Del, // tp_free +}; + + namespace cfield_descriptor { static void Dealloc(CFieldDescriptor* self) { - Py_CLEAR(self->descriptor_field); Py_TYPE(self)->tp_free(reinterpret_cast(self)); } @@ -98,7 +169,7 @@ static PyObject* GetID(CFieldDescriptor *self, void *closure) { static PyGetSetDef Getters[] = { { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, - { C("name"), (getter)GetName, NULL, "last name", NULL}, + { C("name"), (getter)GetName, NULL, "Unqualified name", NULL}, { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL}, { C("label"), (getter)GetLabel, NULL, "Label", NULL}, { C("id"), (getter)GetID, NULL, "ID", NULL}, @@ -151,13 +222,56 @@ PyTypeObject CFieldDescriptor_Type = { PyObject_Del, // tp_free }; + namespace cdescriptor_pool { -static void Dealloc(CDescriptorPool* self) { +PyDescriptorPool* NewDescriptorPool() { + PyDescriptorPool* cdescriptor_pool = PyObject_New( + PyDescriptorPool, &PyDescriptorPool_Type); + if (cdescriptor_pool == NULL) { + return NULL; + } + + // Build a DescriptorPool for messages only declared in Python libraries. + // generated_pool() contains all messages linked in C++ libraries, and is used + // as underlay. + cdescriptor_pool->pool = new google::protobuf::DescriptorPool( + google::protobuf::DescriptorPool::generated_pool()); + + // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same + // storage. + cdescriptor_pool->classes_by_descriptor = + new PyDescriptorPool::ClassesByMessageMap(); + + return cdescriptor_pool; +} + +static void Dealloc(PyDescriptorPool* self) { + for (auto it : (*self->classes_by_descriptor)) { + Py_DECREF(it.second); + } + delete self->classes_by_descriptor; Py_TYPE(self)->tp_free(reinterpret_cast(self)); } -static PyObject* NewCDescriptor( +const google::protobuf::Descriptor* FindMessageTypeByName(PyDescriptorPool* self, + const string& name) { + return self->pool->FindMessageTypeByName(name); +} + +static PyObject* NewCMessageDescriptor( + const google::protobuf::Descriptor* message_descriptor) { + CMessageDescriptor* cmessage_descriptor = PyObject_New( + CMessageDescriptor, &CMessageDescriptor_Type); + if (cmessage_descriptor == NULL) { + return NULL; + } + cmessage_descriptor->descriptor = message_descriptor; + + return reinterpret_cast(cmessage_descriptor); +} + +static PyObject* NewCFieldDescriptor( const google::protobuf::FieldDescriptor* field_descriptor) { CFieldDescriptor* cfield_descriptor = PyObject_New( CFieldDescriptor, &CFieldDescriptor_Type); @@ -165,12 +279,61 @@ static PyObject* NewCDescriptor( return NULL; } cfield_descriptor->descriptor = field_descriptor; - cfield_descriptor->descriptor_field = NULL; return reinterpret_cast(cfield_descriptor); } -PyObject* FindFieldByName(CDescriptorPool* self, PyObject* name) { +// Add a message class to our database. +const google::protobuf::Descriptor* RegisterMessageClass( + PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) { + ScopedPyObjectPtr full_message_name( + PyObject_GetAttrString(descriptor, "full_name")); + const char* full_name = PyString_AsString(full_message_name); + if (full_name == NULL) { + return NULL; + } + const Descriptor *message_descriptor = + self->pool->FindMessageTypeByName(full_name); + if (!message_descriptor) { + PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'", + full_name); + return NULL; + } + Py_INCREF(message_class); + auto ret = self->classes_by_descriptor->insert( + make_pair(message_descriptor, message_class)); + if (!ret.second) { + // Update case: DECREF the previous value. + Py_DECREF(ret.first->second); + ret.first->second = message_class; + } + + // Also add the C++ descriptor to the Python descriptor class. + ScopedPyObjectPtr cdescriptor(NewCMessageDescriptor(message_descriptor)); + if (cdescriptor == NULL) { + return NULL; + } + if (PyObject_SetAttrString( + descriptor, "_cdescriptor", cdescriptor) < 0) { + return NULL; + } + return message_descriptor; +} + +// Retrieve the message class added to our database. +PyObject *GetMessageClass(PyDescriptorPool* self, + const Descriptor *message_descriptor) { + auto ret = self->classes_by_descriptor->find(message_descriptor); + if (ret == self->classes_by_descriptor->end()) { + PyErr_Format(PyExc_TypeError, "No message class registered for '%s'", + message_descriptor->full_name().c_str()); + return NULL; + } else { + return ret->second; + } +} + +PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name) { const char* full_field_name = PyString_AsString(name); if (full_field_name == NULL) { return NULL; @@ -186,10 +349,10 @@ PyObject* FindFieldByName(CDescriptorPool* self, PyObject* name) { return NULL; } - return NewCDescriptor(field_descriptor); + return NewCFieldDescriptor(field_descriptor); } -PyObject* FindExtensionByName(CDescriptorPool* self, PyObject* arg) { +PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) { const char* full_field_name = PyString_AsString(arg); if (full_field_name == NULL) { return NULL; @@ -203,7 +366,7 @@ PyObject* FindExtensionByName(CDescriptorPool* self, PyObject* arg) { return NULL; } - return NewCDescriptor(field_descriptor); + return NewCFieldDescriptor(field_descriptor); } static PyMethodDef Methods[] = { @@ -220,12 +383,12 @@ static PyMethodDef Methods[] = { } // namespace cdescriptor_pool -PyTypeObject CDescriptorPool_Type = { +PyTypeObject PyDescriptorPool_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) C("google.protobuf.internal." "_net_proto2___python." "CFieldDescriptor"), // tp_name - sizeof(CDescriptorPool), // tp_basicsize + sizeof(PyDescriptorPool), // tp_basicsize 0, // tp_itemsize (destructor)cdescriptor_pool::Dealloc, // tp_dealloc 0, // tp_print @@ -259,29 +422,11 @@ PyTypeObject CDescriptorPool_Type = { 0, // tp_descr_set 0, // tp_dictoffset 0, // tp_init - PyType_GenericAlloc, // tp_alloc - PyType_GenericNew, // tp_new + 0, // tp_alloc + 0, // tp_new PyObject_Del, // tp_free }; -google::protobuf::DescriptorPool* GetDescriptorPool() { - if (g_descriptor_pool == NULL) { - g_descriptor_pool = new google::protobuf::DescriptorPool( - google::protobuf::DescriptorPool::generated_pool()); - } - return g_descriptor_pool; -} - -PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) { - CDescriptorPool* cdescriptor_pool = PyObject_New( - CDescriptorPool, &CDescriptorPool_Type); - if (cdescriptor_pool == NULL) { - return NULL; - } - cdescriptor_pool->pool = GetDescriptorPool(); - return reinterpret_cast(cdescriptor_pool); -} - // Collects errors that occur during proto file building to allow them to be // propagated in the python exception instead of only living in ERROR logs. @@ -321,6 +466,8 @@ PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) { return NULL; } + // If the file was already part of a C++ library, all its descriptors are in + // the underlying pool. No need to do anything else. if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName( file_proto.name()) != NULL) { Py_RETURN_NONE; @@ -328,8 +475,8 @@ PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) { BuildFileErrorCollector error_collector; const google::protobuf::FileDescriptor* descriptor = - GetDescriptorPool()->BuildFileCollectingErrors(file_proto, - &error_collector); + GetDescriptorPool()->pool->BuildFileCollectingErrors(file_proto, + &error_collector); if (descriptor == NULL) { PyErr_Format(PyExc_TypeError, "Couldn't build proto file into descriptor pool!\n%s", @@ -341,12 +488,13 @@ PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) { } bool InitDescriptor() { - CFieldDescriptor_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&CMessageDescriptor_Type) < 0) + return false; if (PyType_Ready(&CFieldDescriptor_Type) < 0) return false; - CDescriptorPool_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&CDescriptorPool_Type) < 0) + PyDescriptorPool_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyDescriptorPool_Type) < 0) return false; return true; diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h index ae7a1b9c..9e5957b5 100644 --- a/python/google/protobuf/pyext/descriptor.h +++ b/python/google/protobuf/pyext/descriptor.h @@ -36,6 +36,8 @@ #include #include +#include + #include #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) @@ -48,46 +50,90 @@ namespace google { namespace protobuf { namespace python { +typedef struct CMessageDescriptor { + PyObject_HEAD + + // The proto2 descriptor that this object represents. + const google::protobuf::Descriptor* descriptor; +} CMessageDescriptor; + + typedef struct CFieldDescriptor { PyObject_HEAD // The proto2 descriptor that this object represents. const google::protobuf::FieldDescriptor* descriptor; - - // Reference to the original field object in the Python DESCRIPTOR. - PyObject* descriptor_field; } CFieldDescriptor; -typedef struct { + +// Wraps operations to the global DescriptorPool which contains information +// about all messages and fields. +// +// There is normally one pool per process. We make it a Python object only +// because it contains many Python references. +// TODO(amauryfa): See whether such objects can appear in reference cycles, and +// consider adding support for the cyclic GC. +// +// "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool +// namespace. +typedef struct PyDescriptorPool { PyObject_HEAD - const google::protobuf::DescriptorPool* pool; -} CDescriptorPool; + google::protobuf::DescriptorPool* pool; + // Make our own mapping to retrieve Python classes from C++ descriptors. + // + // Descriptor pointers stored here are owned by the DescriptorPool above. + // Python references to classes are owned by this PyDescriptorPool. + typedef hash_map ClassesByMessageMap; + ClassesByMessageMap *classes_by_descriptor; +} PyDescriptorPool; + + +extern PyTypeObject CMessageDescriptor_Type; extern PyTypeObject CFieldDescriptor_Type; -extern PyTypeObject CDescriptorPool_Type; +extern PyTypeObject PyDescriptorPool_Type; + namespace cdescriptor_pool { +// Builds a new DescriptorPool. Normally called only once per process. +PyDescriptorPool* NewDescriptorPool(); + +// Looks up a message by name. +// Returns a message Descriptor, or NULL if not found. +const google::protobuf::Descriptor* FindMessageTypeByName(PyDescriptorPool* self, + const string& name); + +// Registers a new Python class for the given message descriptor. +// Returns the message Descriptor. +// On error, returns NULL with a Python exception set. +const google::protobuf::Descriptor* RegisterMessageClass( + PyDescriptorPool* self, PyObject *message_class, PyObject *descriptor); + +// Retrieves the Python class registered with the given message descriptor. +// +// Returns a *borrowed* reference if found, otherwise returns NULL with an +// exception set. +PyObject *GetMessageClass(PyDescriptorPool* self, + const Descriptor *message_descriptor); + // Looks up a field by name. Returns a CDescriptor corresponding to // the field on success, or NULL on failure. // // Returns a new reference. -PyObject* FindFieldByName(CDescriptorPool* self, PyObject* name); +PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name); // Looks up an extension by name. Returns a CDescriptor corresponding // to the field on success, or NULL on failure. // // Returns a new reference. -PyObject* FindExtensionByName(CDescriptorPool* self, PyObject* arg); - +PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg); } // namespace cdescriptor_pool -PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args); PyObject* Python_BuildFile(PyObject* ignored, PyObject* args); bool InitDescriptor(); -google::protobuf::DescriptorPool* GetDescriptorPool(); } // namespace python } // namespace protobuf diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc index 3861c794..d83b57d5 100644 --- a/python/google/protobuf/pyext/extension_dict.cc +++ b/python/google/protobuf/pyext/extension_dict.cc @@ -62,22 +62,6 @@ static google::protobuf::Message* GetMessage(ExtensionDict* self) { } } -CFieldDescriptor* InternalGetCDescriptorFromExtension(PyObject* extension) { - PyObject* cdescriptor = PyObject_GetAttrString(extension, "_cdescriptor"); - if (cdescriptor == NULL) { - PyErr_SetString(PyExc_KeyError, "Unregistered extension."); - return NULL; - } - if (!PyObject_TypeCheck(cdescriptor, &CFieldDescriptor_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a CFieldDescriptor"); - Py_DECREF(cdescriptor); - return NULL; - } - CFieldDescriptor* descriptor = - reinterpret_cast(cdescriptor); - return descriptor; -} - PyObject* len(ExtensionDict* self) { #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(PyDict_Size(self->values)); @@ -118,16 +102,15 @@ int ReleaseExtension(ExtensionDict* self, } PyObject* subscript(ExtensionDict* self, PyObject* key) { - CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension( - key); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(key); + if (descriptor == NULL) { return NULL; } - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast(cdescriptor)); - const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor; - if (descriptor == NULL) { + if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) { return NULL; } + if (descriptor->label() != FieldDescriptor::LABEL_REPEATED && descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { return cmessage::InternalGetScalar(self->parent, descriptor); @@ -142,7 +125,7 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { if (descriptor->label() != FieldDescriptor::LABEL_REPEATED && descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyObject* sub_message = cmessage::InternalGetSubMessage( - self->parent, cdescriptor); + self->parent, descriptor); if (sub_message == NULL) { return NULL; } @@ -152,33 +135,21 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - // COPIED - PyObject* py_container = PyObject_CallObject( - reinterpret_cast(&RepeatedCompositeContainer_Type), - NULL); + PyObject *message_class = cdescriptor_pool::GetMessageClass( + GetDescriptorPool(), descriptor->message_type()); + if (message_class == NULL) { + return NULL; + } + PyObject* py_container = repeated_composite_container::NewContainer( + self->parent, descriptor, message_class); if (py_container == NULL) { return NULL; } - RepeatedCompositeContainer* container = - reinterpret_cast(py_container); - PyObject* field = cdescriptor->descriptor_field; - PyObject* message_type = PyObject_GetAttrString(field, "message_type"); - PyObject* concrete_class = PyObject_GetAttrString(message_type, - "_concrete_class"); - container->owner = self->owner; - container->parent = self->parent; - container->message = self->parent->message; - container->parent_field = cdescriptor; - container->subclass_init = concrete_class; - Py_DECREF(message_type); PyDict_SetItem(self->values, key, py_container); return py_container; } else { - // COPIED - ScopedPyObjectPtr init_args(PyTuple_Pack(2, self->parent, cdescriptor)); - PyObject* py_container = PyObject_CallObject( - reinterpret_cast(&RepeatedScalarContainer_Type), - init_args); + PyObject* py_container = repeated_scalar_container::NewContainer( + self->parent, descriptor); if (py_container == NULL) { return NULL; } @@ -191,13 +162,15 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { } int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) { - CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension( - key); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(key); + if (descriptor == NULL) { + return -1; + } + if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) { return -1; } - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast(cdescriptor)); - const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor; + if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL || descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite " @@ -214,20 +187,18 @@ int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) { } PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) { - CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension( - extension); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(extension); + if (descriptor == NULL) { return NULL; } - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast(cdescriptor)); PyObject* value = PyDict_GetItem(self->values, extension); if (value != NULL) { - if (ReleaseExtension(self, value, cdescriptor->descriptor) < 0) { + if (ReleaseExtension(self, value, descriptor) < 0) { return NULL; } } - if (cmessage::ClearFieldByDescriptor(self->parent, - cdescriptor->descriptor) == NULL) { + if (cmessage::ClearFieldByDescriptor(self->parent, descriptor) == NULL) { return NULL; } if (PyDict_DelItem(self->values, extension) < 0) { @@ -237,14 +208,12 @@ PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) { } PyObject* HasExtension(ExtensionDict* self, PyObject* extension) { - CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension( - extension); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(extension); + if (descriptor == NULL) { return NULL; } - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast(cdescriptor)); - PyObject* result = cmessage::HasFieldByDescriptor( - self->parent, cdescriptor->descriptor); + PyObject* result = cmessage::HasFieldByDescriptor(self->parent, descriptor); return result; } @@ -263,11 +232,18 @@ PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) { } } -int init(ExtensionDict* self, PyObject* args, PyObject* kwargs) { - self->parent = NULL; - self->message = NULL; +ExtensionDict* NewExtensionDict(CMessage *parent) { + ExtensionDict* self = reinterpret_cast( + PyType_GenericAlloc(&ExtensionDict_Type, 0)); + if (self == NULL) { + return NULL; + } + + self->parent = parent; // Store a borrowed reference. + self->message = parent->message; + self->owner = parent->owner; self->values = PyDict_New(); - return 0; + return self; } void dealloc(ExtensionDict* self) { @@ -330,7 +306,7 @@ PyTypeObject ExtensionDict_Type = { 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset - (initproc)extension_dict::init, // tp_init + 0, // tp_init }; } // namespace python diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h index 13c874a4..47625e23 100644 --- a/python/google/protobuf/pyext/extension_dict.h +++ b/python/google/protobuf/pyext/extension_dict.h @@ -53,13 +53,26 @@ using internal::shared_ptr; namespace python { struct CMessage; -struct CFieldDescriptor; typedef struct ExtensionDict { PyObject_HEAD; + + // This is the top-level C++ Message object that owns the whole + // proto tree. Every Python container class holds a + // reference to it in order to keep it alive as long as there's a + // Python object that references any part of the tree. shared_ptr owner; + + // Weak reference to parent message. Used to make sure + // the parent is writable when an extension field is modified. CMessage* parent; + + // Pointer to the C++ Message that this ExtensionDict extends. + // Not owned by us. Message* message; + + // A dict of child messages, indexed by Extension descriptors. + // Similar to CMessage::composite_fields. PyObject* values; } ExtensionDict; @@ -67,11 +80,8 @@ extern PyTypeObject ExtensionDict_Type; namespace extension_dict { -// Gets the _cdescriptor reference to a CFieldDescriptor object given a -// python descriptor object. -// -// Returns a new reference. -CFieldDescriptor* InternalGetCDescriptorFromExtension(PyObject* extension); +// Builds an Extensions dict for a specific message. +ExtensionDict* NewExtensionDict(CMessage *parent); // Gets the number of extension values in this ExtensionDict as a python object. // diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 9fb7083f..cd956e0e 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -71,7 +71,7 @@ #error "Python 3.0 - 3.2 are not supported." #else #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob)) + (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) #endif #endif @@ -81,7 +81,9 @@ namespace python { // Forward declarations namespace cmessage { -static PyObject* GetDescriptor(CMessage* self, PyObject* name); +static const google::protobuf::FieldDescriptor* GetFieldDescriptor( + CMessage* self, PyObject* name); +static const google::protobuf::Descriptor* GetMessageDescriptor(PyTypeObject* cls); static string GetMessageName(CMessage* self); int InternalReleaseFieldByDescriptor( const google::protobuf::FieldDescriptor* field_descriptor, @@ -147,12 +149,15 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { PyObject* key; PyObject* field; + // Never use self->message in this function, it may be already freed. + const google::protobuf::Descriptor* message_descriptor = + cmessage::GetMessageDescriptor(Py_TYPE(self)); + // Visit normal fields. while (PyDict_Next(self->composite_fields, &pos, &key, &field)) { - PyObject* cdescriptor = cmessage::GetDescriptor(self, key); - if (cdescriptor != NULL) { - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast(cdescriptor)->descriptor; + const google::protobuf::FieldDescriptor* descriptor = + message_descriptor->FindFieldByName(PyString_AsString(key)); + if (descriptor != NULL) { if (VisitCompositeField(descriptor, field, visitor) == -1) return -1; } @@ -161,11 +166,11 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { // Visit extension fields. if (self->extensions != NULL) { while (PyDict_Next(self->extensions->values, &pos, &key, &field)) { - CFieldDescriptor* cdescriptor = - extension_dict::InternalGetCDescriptorFromExtension(key); - if (cdescriptor == NULL) + const google::protobuf::FieldDescriptor* descriptor = + cmessage::GetExtensionDescriptor(key); + if (descriptor == NULL) return -1; - if (VisitCompositeField(cdescriptor->descriptor, field, visitor) == -1) + if (VisitCompositeField(descriptor, field, visitor) == -1) return -1; } } @@ -191,18 +196,19 @@ PyObject* PickleError_class; // Constant PyString values used for GetAttr/GetItem. static PyObject* kDESCRIPTOR; -static PyObject* k__descriptors; +static PyObject* k_cdescriptor; static PyObject* kfull_name; static PyObject* kname; -static PyObject* kmessage_type; -static PyObject* kis_extendable; static PyObject* kextensions_by_name; static PyObject* k_extensions_by_name; static PyObject* k_extensions_by_number; -static PyObject* k_concrete_class; static PyObject* kfields_by_name; -static CDescriptorPool* descriptor_pool; +static PyDescriptorPool* descriptor_pool; + +PyDescriptorPool* GetDescriptorPool() { + return descriptor_pool; +} /* Is 64bit */ void FormatTypeError(PyObject* arg, char* expected_types) { @@ -313,12 +319,12 @@ bool CheckAndSetString( } if (PyBytes_Check(arg)) { - PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", NULL); + PyObject* unicode = PyUnicode_FromEncodedObject(arg, "utf-8", NULL); if (unicode == NULL) { PyObject* repr = PyObject_Repr(arg); PyErr_Format(PyExc_ValueError, - "%s has type str, but isn't in 7-bit ASCII " - "encoding. Non-ASCII strings must be converted to " + "%s has type str, but isn't valid UTF-8 " + "encoding. Non-UTF-8 strings must be converted to " "unicode objects before being added.", PyString_AsString(repr)); Py_DECREF(repr); @@ -335,12 +341,9 @@ bool CheckAndSetString( PyObject* encoded_string = NULL; if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) { if (PyBytes_Check(arg)) { -#if PY_MAJOR_VERSION < 3 - encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL); -#else + // The bytes were already validated as correctly encoded UTF-8 above. encoded_string = arg; // Already encoded. Py_INCREF(encoded_string); -#endif } else { encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL); } @@ -391,6 +394,17 @@ PyObject* ToStringObject( return result; } +bool CheckFieldBelongsToMessage(const google::protobuf::FieldDescriptor* field_descriptor, + const google::protobuf::Message* message) { + if (message->GetDescriptor() == field_descriptor->containing_type()) { + return true; + } + PyErr_Format(PyExc_KeyError, "Field '%s' does not belong to message '%s'", + field_descriptor->full_name().c_str(), + message->GetDescriptor()->full_name().c_str()); + return false; +} + google::protobuf::DynamicMessageFactory* global_message_factory; namespace cmessage { @@ -489,7 +503,7 @@ int AssureWritable(CMessage* self) { google::protobuf::Message* parent_message = self->parent->message; google::protobuf::Message* mutable_message = GetMutableMessage( self->parent, - self->parent_field->descriptor); + self->parent_field_descriptor); if (mutable_message == NULL) { return -1; } @@ -512,26 +526,61 @@ int AssureWritable(CMessage* self) { // --- Globals: -static PyObject* GetDescriptor(CMessage* self, PyObject* name) { - PyObject* descriptors = - PyDict_GetItem(Py_TYPE(self)->tp_dict, k__descriptors); - if (descriptors == NULL) { - PyErr_SetString(PyExc_TypeError, "No __descriptors"); +// Retrieve the C++ Descriptor of a message class. +// On error, returns NULL with an exception set. +static const google::protobuf::Descriptor* GetMessageDescriptor(PyTypeObject* cls) { + ScopedPyObjectPtr descriptor(PyObject_GetAttr( + reinterpret_cast(cls), kDESCRIPTOR)); + if (descriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); + return NULL; + } + ScopedPyObjectPtr cdescriptor(PyObject_GetAttr(descriptor, k_cdescriptor)); + if (cdescriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "Unregistered message."); + return NULL; + } + if (!PyObject_TypeCheck(cdescriptor, &CMessageDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not a CMessageDescriptor"); return NULL; } + return reinterpret_cast(cdescriptor.get())->descriptor; +} - return PyDict_GetItem(descriptors, name); +// Retrieve a C++ FieldDescriptor for a message attribute. +// The C++ message must be valid. +// TODO(amauryfa): This function should stay internal, because exception +// handling is not consistent. +static const google::protobuf::FieldDescriptor* GetFieldDescriptor( + CMessage* self, PyObject* name) { + const google::protobuf::Descriptor *message_descriptor = self->message->GetDescriptor(); + const char* field_name = PyString_AsString(name); + if (field_name == NULL) { + return NULL; + } + const google::protobuf::FieldDescriptor *field_descriptor = + message_descriptor->FindFieldByName(field_name); + if (field_descriptor == NULL) { + // Note: No exception is set! + return NULL; + } + return field_descriptor; } -static const google::protobuf::Message* CreateMessage(const char* message_type) { - string message_name(message_type); - const google::protobuf::Descriptor* descriptor = - GetDescriptorPool()->FindMessageTypeByName(message_name); - if (descriptor == NULL) { - PyErr_SetString(PyExc_TypeError, message_type); +// Retrieve a C++ FieldDescriptor for an extension handle. +const google::protobuf::FieldDescriptor* GetExtensionDescriptor(PyObject* extension) { + ScopedPyObjectPtr cdescriptor( + PyObject_GetAttrString(extension, "_cdescriptor")); + if (cdescriptor == NULL) { + PyErr_SetString(PyExc_KeyError, "Unregistered extension."); + return NULL; + } + if (!PyObject_TypeCheck(cdescriptor, &CFieldDescriptor_Type)) { + PyErr_SetString(PyExc_TypeError, "Not a CFieldDescriptor"); + Py_DECREF(cdescriptor); return NULL; } - return global_message_factory->GetPrototype(descriptor); + return reinterpret_cast(cdescriptor.get())->descriptor; } // If cmessage_list is not NULL, this function releases values into the @@ -627,39 +676,8 @@ int InternalDeleteRepeatedField( return 0; } -int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { - ScopedPyObjectPtr descriptor; - if (arg == NULL) { - descriptor.reset( - PyObject_GetAttr(reinterpret_cast(self), kDESCRIPTOR)); - if (descriptor == NULL) { - return NULL; - } - } else { - descriptor.reset(arg); - descriptor.inc(); - } - ScopedPyObjectPtr is_extendable(PyObject_GetAttr(descriptor, kis_extendable)); - if (is_extendable == NULL) { - return NULL; - } - int retcode = PyObject_IsTrue(is_extendable); - if (retcode == -1) { - return NULL; - } - if (retcode) { - PyObject* py_extension_dict = PyObject_CallObject( - reinterpret_cast(&ExtensionDict_Type), NULL); - if (py_extension_dict == NULL) { - return NULL; - } - ExtensionDict* extension_dict = reinterpret_cast( - py_extension_dict); - extension_dict->parent = self; - extension_dict->message = self->message; - self->extensions = extension_dict; - } - +// Initializes fields of a message. Used in constructors. +int InitAttributes(CMessage* self, PyObject* kwargs) { if (kwargs == NULL) { return 0; } @@ -672,14 +690,12 @@ int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { PyErr_SetString(PyExc_ValueError, "Field name must be a string"); return -1; } - PyObject* py_cdescriptor = GetDescriptor(self, name); - if (py_cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = GetFieldDescriptor(self, name); + if (descriptor == NULL) { PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.", PyString_AsString(name)); return -1; } - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast(py_cdescriptor)->descriptor; if (descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { ScopedPyObjectPtr container(GetAttr(self, name)); if (container == NULL) { @@ -719,15 +735,19 @@ int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) { return 0; } -static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) { - CMessage* self = reinterpret_cast(type->tp_alloc(type, 0)); +// Allocates an incomplete Python Message: the caller must fill self->message, +// self->owner and eventually self->parent. +CMessage* NewEmptyMessage(PyObject* type, + const google::protobuf::Descriptor *descriptor) { + CMessage* self = reinterpret_cast( + PyType_GenericAlloc(reinterpret_cast(type), 0)); if (self == NULL) { return NULL; } self->message = NULL; self->parent = NULL; - self->parent_field = NULL; + self->parent_field_descriptor = NULL; self->read_only = false; self->extensions = NULL; @@ -735,43 +755,58 @@ static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) { if (self->composite_fields == NULL) { return NULL; } - return reinterpret_cast(self); -} - -PyObject* NewEmpty(PyObject* type) { - return New(reinterpret_cast(type), NULL, NULL); -} -static int Init(CMessage* self, PyObject* args, PyObject* kwargs) { - if (kwargs == NULL) { - // TODO(anuraag): Set error - return -1; + // If there are extension_ranges, the message is "extendable". Allocate a + // dictionary to store the extension fields. + if (descriptor->extension_range_count() > 0) { + // TODO(amauryfa): Delay the construction of this dict until extensions are + // really used on the object. + ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self); + if (extension_dict == NULL) { + return NULL; + } + self->extensions = extension_dict; } - PyObject* descriptor = PyTuple_GetItem(args, 0); - if (descriptor == NULL || PyTuple_Size(args) != 1) { - PyErr_SetString(PyExc_ValueError, "args must contain one arg: descriptor"); - return -1; - } + return self; +} - ScopedPyObjectPtr py_message_type(PyObject_GetAttr(descriptor, kfull_name)); - if (py_message_type == NULL) { - return -1; +// The __new__ method of Message classes. +// Creates a new C++ message and takes ownership. +static PyObject* New(PyTypeObject* type, + PyObject* unused_args, PyObject* unused_kwargs) { + // Retrieve the message descriptor and the default instance (=prototype). + const google::protobuf::Descriptor* message_descriptor = GetMessageDescriptor(type); + if (message_descriptor == NULL) { + return NULL; } - - const char* message_type = PyString_AsString(py_message_type.get()); - const google::protobuf::Message* message = CreateMessage(message_type); - if (message == NULL) { - return -1; + const google::protobuf::Message* default_message = + global_message_factory->GetPrototype(message_descriptor); + if (default_message == NULL) { + PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); + return NULL; } - self->message = message->New(); + CMessage* self = NewEmptyMessage(reinterpret_cast(type), + message_descriptor); + if (self == NULL) { + return NULL; + } + self->message = default_message->New(); self->owner.reset(self->message); - if (InitAttributes(self, descriptor, kwargs) < 0) { + return reinterpret_cast(self); +} + +// The __init__ method of Message classes. +// It initializes fields from keywords passed to the constructor. +static int Init(CMessage* self, PyObject* args, PyObject* kwargs) { + if (PyTuple_Size(args) != 0) { + PyErr_SetString(PyExc_TypeError, "No positional arguments allowed"); return -1; } - return 0; + + return InitAttributes(self, kwargs); } // --------------------------------------------------------------------- @@ -853,9 +888,7 @@ PyObject* IsInitialized(CMessage* self, PyObject* args) { PyObject* HasFieldByDescriptor( CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor) { google::protobuf::Message* message = self->message; - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString(PyExc_KeyError, - "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return NULL; } if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { @@ -1048,7 +1081,7 @@ int ReleaseSubMessage(google::protobuf::Message* message, child_cmessage->message = released_message.get(); child_cmessage->owner.swap(released_message); child_cmessage->parent = NULL; - child_cmessage->parent_field = NULL; + child_cmessage->parent_field_descriptor = NULL; child_cmessage->read_only = false; return ForEachCompositeField(child_cmessage, SetOwnerVisitor(child_cmessage->owner)); @@ -1090,10 +1123,8 @@ int InternalReleaseFieldByDescriptor( int InternalReleaseField(CMessage* self, PyObject* composite_field, PyObject* name) { - PyObject* cdescriptor = GetDescriptor(self, name); - if (cdescriptor != NULL) { - const google::protobuf::FieldDescriptor* descriptor = - reinterpret_cast(cdescriptor)->descriptor; + const google::protobuf::FieldDescriptor* descriptor = GetFieldDescriptor(self, name); + if (descriptor != NULL) { return InternalReleaseFieldByDescriptor( descriptor, composite_field, self->message); } @@ -1104,9 +1135,7 @@ int InternalReleaseField(CMessage* self, PyObject* composite_field, PyObject* ClearFieldByDescriptor( CMessage* self, const google::protobuf::FieldDescriptor* descriptor) { - if (!FIELD_BELONGS_TO_MESSAGE(descriptor, self->message)) { - PyErr_SetString(PyExc_KeyError, - "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(descriptor, self->message)) { return NULL; } AssureWritable(self); @@ -1177,15 +1206,10 @@ PyObject* Clear(CMessage* self) { // fields have been released. if (self->extensions != NULL) { Py_CLEAR(self->extensions); - PyObject* py_extension_dict = PyObject_CallObject( - reinterpret_cast(&ExtensionDict_Type), NULL); - if (py_extension_dict == NULL) { + ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self); + if (extension_dict == NULL) { return NULL; } - ExtensionDict* extension_dict = reinterpret_cast( - py_extension_dict); - extension_dict->parent = self; - extension_dict->message = self->message; self->extensions = extension_dict; } PyDict_Clear(self->composite_fields); @@ -1196,8 +1220,8 @@ PyObject* Clear(CMessage* self) { // --------------------------------------------------------------------- static string GetMessageName(CMessage* self) { - if (self->parent_field != NULL) { - return self->parent_field->descriptor->full_name(); + if (self->parent_field_descriptor != NULL) { + return self->parent_field_descriptor->full_name(); } else { return self->message->GetDescriptor()->full_name(); } @@ -1219,7 +1243,7 @@ static PyObject* SerializeToString(CMessage* self, PyObject* args) { return NULL; } PyErr_Format(EncodeError_class, "Message %s is missing required fields: %s", - GetMessageName(self).c_str(), PyString_AsString(joined.get())); + GetMessageName(self).c_str(), PyString_AsString(joined)); return NULL; } int size = self->message->ByteSize(); @@ -1361,7 +1385,7 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { AssureWritable(self); google::protobuf::io::CodedInputStream input( reinterpret_cast(data), data_length); - input.SetExtensionRegistry(GetDescriptorPool(), global_message_factory); + input.SetExtensionRegistry(descriptor_pool->pool, global_message_factory); bool success = self->message->MergePartialFromCodedStream(&input); if (success) { return PyInt_FromLong(input.CurrentPosition()); @@ -1421,15 +1445,11 @@ static PyObject* RegisterExtension(PyObject* cls, return NULL; } - CFieldDescriptor* cdescriptor = - extension_dict::InternalGetCDescriptorFromExtension(extension_handle); - ScopedPyObjectPtr py_cdescriptor(reinterpret_cast(cdescriptor)); - if (cdescriptor == NULL) { + const google::protobuf::FieldDescriptor* descriptor = + GetExtensionDescriptor(extension_handle); + if (descriptor == NULL) { return NULL; } - Py_INCREF(extension_handle); - cdescriptor->descriptor_field = extension_handle; - const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor; // Check if it's a message set if (descriptor->is_extension() && descriptor->containing_type()->options().message_set_wire_format() && @@ -1608,8 +1628,14 @@ static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) { } if (opid == Py_EQ || opid == Py_NE) { ScopedPyObjectPtr self_fields(ListFields(self)); + if (!self_fields) { + return NULL; + } ScopedPyObjectPtr other_fields(ListFields( reinterpret_cast(other))); + if (!other_fields) { + return NULL; + } return PyObject_RichCompare(self_fields, other_fields, opid); } else { Py_INCREF(Py_NotImplemented); @@ -1623,9 +1649,7 @@ PyObject* InternalGetScalar( google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return NULL; } @@ -1701,43 +1725,31 @@ PyObject* InternalGetScalar( return result; } -PyObject* InternalGetSubMessage(CMessage* self, - CFieldDescriptor* cfield_descriptor) { - PyObject* field = cfield_descriptor->descriptor_field; - ScopedPyObjectPtr message_type(PyObject_GetAttr(field, kmessage_type)); - if (message_type == NULL) { - return NULL; - } - ScopedPyObjectPtr concrete_class( - PyObject_GetAttr(message_type, k_concrete_class)); - if (concrete_class == NULL) { +PyObject* InternalGetSubMessage( + CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor) { + const google::protobuf::Reflection* reflection = self->message->GetReflection(); + const google::protobuf::Message& sub_message = reflection->GetMessage( + *self->message, field_descriptor, global_message_factory); + + PyObject *message_class = cdescriptor_pool::GetMessageClass( + descriptor_pool, field_descriptor->message_type()); + if (message_class == NULL) { return NULL; } - PyObject* py_cmsg = cmessage::NewEmpty(concrete_class); - if (py_cmsg == NULL) { + + CMessage* cmsg = cmessage::NewEmptyMessage(message_class, + sub_message.GetDescriptor()); + if (cmsg == NULL) { return NULL; } - if (!PyObject_TypeCheck(py_cmsg, &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Not a CMessage!"); - } - CMessage* cmsg = reinterpret_cast(py_cmsg); - const google::protobuf::FieldDescriptor* field_descriptor = - cfield_descriptor->descriptor; - const google::protobuf::Reflection* reflection = self->message->GetReflection(); - const google::protobuf::Message& sub_message = reflection->GetMessage( - *self->message, field_descriptor, global_message_factory); cmsg->owner = self->owner; cmsg->parent = self; - cmsg->parent_field = cfield_descriptor; + cmsg->parent_field_descriptor = field_descriptor; cmsg->read_only = !reflection->HasField(*self->message, field_descriptor); cmsg->message = const_cast(&sub_message); - if (InitAttributes(cmsg, NULL, NULL) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } - return py_cmsg; + return reinterpret_cast(cmsg); } int InternalSetScalar( @@ -1747,9 +1759,7 @@ int InternalSetScalar( google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); + if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return -1; } @@ -1838,25 +1848,35 @@ PyObject* FromString(PyTypeObject* cls, PyObject* serialized) { return NULL; } - if (InitAttributes(cmsg, NULL, NULL) < 0) { - Py_DECREF(py_cmsg); - return NULL; - } return py_cmsg; } + +// Finalize the creation of the Message class. +// Called from its metaclass: GeneratedProtocolMessageType.__init__(). static PyObject* AddDescriptors(PyTypeObject* cls, PyObject* descriptor) { - if (PyObject_SetAttr(reinterpret_cast(cls), - k_extensions_by_name, PyDict_New()) < 0) { - return NULL; - } - if (PyObject_SetAttr(reinterpret_cast(cls), - k_extensions_by_number, PyDict_New()) < 0) { + const google::protobuf::Descriptor* message_descriptor = + cdescriptor_pool::RegisterMessageClass( + descriptor_pool, reinterpret_cast(cls), descriptor); + if (message_descriptor == NULL) { return NULL; } - ScopedPyObjectPtr field_descriptors(PyDict_New()); + // If there are extension_ranges, the message is "extendable", and extension + // classes will register themselves in this class. + if (message_descriptor->extension_range_count() > 0) { + ScopedPyObjectPtr by_name(PyDict_New()); + if (PyObject_SetAttr(reinterpret_cast(cls), + k_extensions_by_name, by_name) < 0) { + return NULL; + } + ScopedPyObjectPtr by_number(PyDict_New()); + if (PyObject_SetAttr(reinterpret_cast(cls), + k_extensions_by_number, by_number) < 0) { + return NULL; + } + } ScopedPyObjectPtr fields(PyObject_GetAttrString(descriptor, "fields")); if (fields == NULL) { @@ -1878,19 +1898,14 @@ static PyObject* AddDescriptors(PyTypeObject* cls, return NULL; } - PyObject* field_descriptor = - cdescriptor_pool::FindFieldByName(descriptor_pool, full_field_name); + ScopedPyObjectPtr field_descriptor( + cdescriptor_pool::FindFieldByName(descriptor_pool, full_field_name)); if (field_descriptor == NULL) { PyErr_SetString(PyExc_TypeError, "Couldn't find field"); return NULL; } - Py_INCREF(field); CFieldDescriptor* cfield_descriptor = reinterpret_cast( - field_descriptor); - cfield_descriptor->descriptor_field = field; - if (PyDict_SetItem(field_descriptors, field_name, field_descriptor) < 0) { - return NULL; - } + field_descriptor.get()); // The FieldDescriptor's name field might either be of type bytes or // of type unicode, depending on whether the FieldDescriptor was @@ -1919,8 +1934,6 @@ static PyObject* AddDescriptors(PyTypeObject* cls, } } - PyDict_SetItem(cls->tp_dict, k__descriptors, field_descriptors); - // Enum Values ScopedPyObjectPtr enum_types(PyObject_GetAttrString(descriptor, "enum_types")); @@ -1994,15 +2007,11 @@ static PyObject* AddDescriptors(PyTypeObject* cls, extension_name, extension_field) == -1) { return NULL; } - ScopedPyObjectPtr py_cfield_descriptor( - PyObject_GetAttrString(extension_field, "_cdescriptor")); - if (py_cfield_descriptor == NULL) { + const google::protobuf::FieldDescriptor* field_descriptor = + GetExtensionDescriptor(extension_field); + if (field_descriptor == NULL) { return NULL; } - CFieldDescriptor* cfield_descriptor = - reinterpret_cast(py_cfield_descriptor.get()); - Py_INCREF(extension_field); - cfield_descriptor->descriptor_field = extension_field; ScopedPyObjectPtr field_name_upcased( PyObject_CallMethod(extension_name, "upper", NULL)); @@ -2015,13 +2024,12 @@ static PyObject* AddDescriptors(PyTypeObject* cls, return NULL; } ScopedPyObjectPtr number(PyInt_FromLong( - cfield_descriptor->descriptor->number())); + field_descriptor->number())); if (number == NULL) { return NULL; } if (PyObject_SetAttr(reinterpret_cast(cls), - field_number_name, PyInt_FromLong( - cfield_descriptor->descriptor->number())) == -1) { + field_number_name, number) == -1) { return NULL; } } @@ -2039,10 +2047,6 @@ PyObject* DeepCopy(CMessage* self, PyObject* arg) { Py_DECREF(clone); return NULL; } - if (InitAttributes(reinterpret_cast(clone), NULL, NULL) < 0) { - Py_DECREF(clone); - return NULL; - } if (MergeFrom(reinterpret_cast(clone), reinterpret_cast(self)) == NULL) { Py_DECREF(clone); @@ -2202,48 +2206,30 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { return value; } - PyObject* descriptor = GetDescriptor(self, name); - if (descriptor != NULL) { - CFieldDescriptor* cdescriptor = - reinterpret_cast(descriptor); - const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor; + const google::protobuf::FieldDescriptor* field_descriptor = GetFieldDescriptor( + self, name); + if (field_descriptor != NULL) { if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { if (field_descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* py_container = PyObject_CallObject( - reinterpret_cast(&RepeatedCompositeContainer_Type), - NULL); - if (py_container == NULL) { + PyObject *message_class = cdescriptor_pool::GetMessageClass( + descriptor_pool, field_descriptor->message_type()); + if (message_class == NULL) { return NULL; } - RepeatedCompositeContainer* container = - reinterpret_cast(py_container); - PyObject* field = cdescriptor->descriptor_field; - PyObject* message_type = PyObject_GetAttr(field, kmessage_type); - if (message_type == NULL) { - return NULL; - } - PyObject* concrete_class = - PyObject_GetAttr(message_type, k_concrete_class); - if (concrete_class == NULL) { + PyObject* py_container = repeated_composite_container::NewContainer( + self, field_descriptor, message_class); + if (py_container == NULL) { return NULL; } - container->parent = self; - container->parent_field = cdescriptor; - container->message = self->message; - container->owner = self->owner; - container->subclass_init = concrete_class; - Py_DECREF(message_type); if (PyDict_SetItem(self->composite_fields, name, py_container) < 0) { Py_DECREF(py_container); return NULL; } return py_container; } else { - ScopedPyObjectPtr init_args(PyTuple_Pack(2, self, cdescriptor)); - PyObject* py_container = PyObject_CallObject( - reinterpret_cast(&RepeatedScalarContainer_Type), - init_args); + PyObject* py_container = repeated_scalar_container::NewContainer( + self, field_descriptor); if (py_container == NULL) { return NULL; } @@ -2256,7 +2242,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { } else { if (field_descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* sub_message = InternalGetSubMessage(self, cdescriptor); + PyObject* sub_message = InternalGetSubMessage(self, field_descriptor); if (PyDict_SetItem(self->composite_fields, name, sub_message) < 0) { Py_DECREF(sub_message); return NULL; @@ -2278,12 +2264,10 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { return -1; } - PyObject* descriptor = GetDescriptor(self, name); - if (descriptor != NULL) { + const google::protobuf::FieldDescriptor* field_descriptor = + GetFieldDescriptor(self, name); + if (field_descriptor != NULL) { AssureWritable(self); - CFieldDescriptor* cdescriptor = - reinterpret_cast(descriptor); - const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor; if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { PyErr_Format(PyExc_AttributeError, "Assignment not allowed to repeated " "field \"%s\" in protocol message object.", @@ -2401,22 +2385,18 @@ void InitGlobals() { kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max); kDESCRIPTOR = PyString_FromString("DESCRIPTOR"); - k__descriptors = PyString_FromString("__descriptors"); + k_cdescriptor = PyString_FromString("_cdescriptor"); kfull_name = PyString_FromString("full_name"); - kis_extendable = PyString_FromString("is_extendable"); kextensions_by_name = PyString_FromString("extensions_by_name"); k_extensions_by_name = PyString_FromString("_extensions_by_name"); k_extensions_by_number = PyString_FromString("_extensions_by_number"); - k_concrete_class = PyString_FromString("_concrete_class"); - kmessage_type = PyString_FromString("message_type"); kname = PyString_FromString("name"); kfields_by_name = PyString_FromString("fields_by_name"); - global_message_factory = new DynamicMessageFactory(GetDescriptorPool()); - global_message_factory->SetDelegateToGeneratedFactory(true); + descriptor_pool = cdescriptor_pool::NewDescriptorPool(); - descriptor_pool = reinterpret_cast( - Python_NewCDescriptorPool(NULL, NULL)); + global_message_factory = new DynamicMessageFactory(descriptor_pool->pool); + global_message_factory->SetDelegateToGeneratedFactory(true); } bool InitProto2MessageModule(PyObject *m) { @@ -2427,19 +2407,32 @@ bool InitProto2MessageModule(PyObject *m) { return false; } - // All three of these are actually set elsewhere, directly onto the child - // protocol buffer message class, but set them here as well to document that - // subclasses need to set these. + // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set + // it here as well to document that subclasses need to set it. PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, kDESCRIPTOR, Py_None); - PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, - k_extensions_by_name, Py_None); - PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, - k_extensions_by_number, Py_None); + // Subclasses with message extensions will override _extensions_by_name and + // _extensions_by_number with fresh mutable dictionaries in AddDescriptors. + // All other classes can share this same immutable mapping. + ScopedPyObjectPtr empty_dict(PyDict_New()); + if (empty_dict == NULL) { + return false; + } + ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict)); + if (immutable_dict == NULL) { + return false; + } + if (PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, + k_extensions_by_name, immutable_dict) < 0) { + return false; + } + if (PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, + k_extensions_by_number, immutable_dict) < 0) { + return false; + } PyModule_AddObject(m, "Message", reinterpret_cast( &google::protobuf::python::CMessage_Type)); - google::protobuf::python::RepeatedScalarContainer_Type.tp_new = PyType_GenericNew; google::protobuf::python::RepeatedScalarContainer_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::RepeatedScalarContainer_Type) < 0) { @@ -2450,7 +2443,6 @@ bool InitProto2MessageModule(PyObject *m) { reinterpret_cast( &google::protobuf::python::RepeatedScalarContainer_Type)); - google::protobuf::python::RepeatedCompositeContainer_Type.tp_new = PyType_GenericNew; google::protobuf::python::RepeatedCompositeContainer_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::RepeatedCompositeContainer_Type) < 0) { @@ -2462,7 +2454,6 @@ bool InitProto2MessageModule(PyObject *m) { reinterpret_cast( &google::protobuf::python::RepeatedCompositeContainer_Type)); - google::protobuf::python::ExtensionDict_Type.tp_new = PyType_GenericNew; google::protobuf::python::ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&google::protobuf::python::ExtensionDict_Type) < 0) { return false; diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index 9f4978f4..73e5a7d3 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -49,12 +49,13 @@ namespace protobuf { class Message; class Reflection; class FieldDescriptor; +class Descriptor; using internal::shared_ptr; namespace python { -struct CFieldDescriptor; +struct PyDescriptorPool; struct ExtensionDict; typedef struct CMessage { @@ -79,13 +80,11 @@ typedef struct CMessage { // to use this pointer will result in a crash. struct CMessage* parent; - // Weak reference to the parent's descriptor that describes this submessage. + // Pointer to the parent's descriptor that describes this submessage. // Used together with the parent's message when making a default message // instance mutable. - // TODO(anuraag): With a bit of work on the Python/C++ layer, it should be - // possible to make this a direct pointer to a C++ FieldDescriptor, this would - // be easier if this implementation replaces upstream. - CFieldDescriptor* parent_field; + // The pointer is owned by the global DescriptorPool. + const google::protobuf::FieldDescriptor* parent_field_descriptor; // Pointer to the C++ Message object for this CMessage. The // CMessage does not own this pointer. @@ -113,8 +112,11 @@ extern PyTypeObject CMessage_Type; namespace cmessage { -// Create a new empty message that can be populated by the parent. -PyObject* NewEmpty(PyObject* type); +// Internal function to create a new empty Message Python object, but with empty +// pointers to the C++ objects. +// The caller must fill self->message, self->owner and eventually self->parent. +CMessage* NewEmptyMessage(PyObject* type, + const google::protobuf::Descriptor* descriptor); // Release a submessage from its proto tree, making it a new top-level messgae. // A new message will be created if this is a read-only default instance. @@ -124,12 +126,16 @@ int ReleaseSubMessage(google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field_descriptor, CMessage* child_cmessage); +// Retrieves the C++ descriptor of a Python Extension descriptor. +// On error, return NULL with an exception set. +const google::protobuf::FieldDescriptor* GetExtensionDescriptor(PyObject* extension); + // Initializes a new CMessage instance for a submessage. Only called once per // submessage as the result is cached in composite_fields. // // Corresponds to reflection api method GetMessage. -PyObject* InternalGetSubMessage(CMessage* self, - CFieldDescriptor* cfield_descriptor); +PyObject* InternalGetSubMessage( + CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor); // Deletes a range of C++ submessages in a repeated field (following a // removal in a RepeatedCompositeContainer). @@ -190,10 +196,8 @@ PyObject* HasFieldByDescriptor( // Corresponds to reflection api method HasField. PyObject* HasField(CMessage* self, PyObject* arg); -// Initializes constants/enum values on a message. This is called by -// RepeatedCompositeContainer and ExtensionDict after calling the constructor. -// TODO(anuraag): Make it always called from within the constructor since it can -int InitAttributes(CMessage* self, PyObject* descriptor, PyObject* kwargs); +// Initializes values of fields on a newly constructed message. +int InitAttributes(CMessage* self, PyObject* kwargs); PyObject* MergeFrom(CMessage* self, PyObject* arg); @@ -218,12 +222,14 @@ int AssureWritable(CMessage* self); } // namespace cmessage + +// Retrieve the global descriptor pool owned by the _message module. +PyDescriptorPool* GetDescriptorPool(); + + /* Is 64bit */ #define IS_64BIT (SIZEOF_LONG == 8) -#define FIELD_BELONGS_TO_MESSAGE(field_descriptor, message) \ - ((message)->GetDescriptor() == (field_descriptor)->containing_type()) - #define FIELD_IS_REPEATED(field_descriptor) \ ((field_descriptor)->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) @@ -296,6 +302,11 @@ bool CheckAndSetString( PyObject* ToStringObject( const google::protobuf::FieldDescriptor* descriptor, string value); +// Check if the passed field descriptor belongs to the given message. +// If not, return false and set a Python exception (a KeyError) +bool CheckFieldBelongsToMessage(const google::protobuf::FieldDescriptor* field_descriptor, + const google::protobuf::Message* message); + extern PyObject* PickleError_class; } // namespace python diff --git a/python/google/protobuf/pyext/proto2_api_test.proto b/python/google/protobuf/pyext/proto2_api_test.proto index 72c31b1c..18aecfb7 100644 --- a/python/google/protobuf/pyext/proto2_api_test.proto +++ b/python/google/protobuf/pyext/proto2_api_test.proto @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +syntax = "proto2"; + import "google/protobuf/internal/cpp/proto1_api_test.proto"; package google.protobuf.python.internal; diff --git a/python/google/protobuf/pyext/python.proto b/python/google/protobuf/pyext/python.proto index d47d402c..cce645d7 100644 --- a/python/google/protobuf/pyext/python.proto +++ b/python/google/protobuf/pyext/python.proto @@ -33,6 +33,7 @@ // These message definitions are used to exercises known corner cases // in the C++ implementation of the Python API. +syntax = "proto2"; package google.protobuf.python.internal; @@ -63,4 +64,5 @@ message TestAllExtensions { extend TestAllExtensions { optional TestAllTypes.NestedMessage optional_nested_message_extension = 1; + repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 2; } diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc index 5c05b3d8..36fe86ae 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.cc +++ b/python/google/protobuf/pyext/repeated_composite_container.cc @@ -65,14 +65,14 @@ namespace repeated_composite_container { #define GOOGLE_CHECK_ATTACHED(self) \ do { \ GOOGLE_CHECK_NOTNULL((self)->message); \ - GOOGLE_CHECK_NOTNULL((self)->parent_field); \ + GOOGLE_CHECK_NOTNULL((self)->parent_field_descriptor); \ } while (0); #define GOOGLE_CHECK_RELEASED(self) \ do { \ GOOGLE_CHECK((self)->owner.get() == NULL); \ GOOGLE_CHECK((self)->message == NULL); \ - GOOGLE_CHECK((self)->parent_field == NULL); \ + GOOGLE_CHECK((self)->parent_field_descriptor == NULL); \ GOOGLE_CHECK((self)->parent == NULL); \ } while (0); @@ -122,7 +122,7 @@ static int InternalQuickSort(RepeatedCompositeContainer* self, google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor; + const google::protobuf::FieldDescriptor* descriptor = self->parent_field_descriptor; Py_ssize_t left; Py_ssize_t right; @@ -202,7 +202,7 @@ static Py_ssize_t Length(RepeatedCompositeContainer* self) { google::protobuf::Message* message = self->message; if (message != NULL) { return message->GetReflection()->FieldSize(*message, - self->parent_field->descriptor); + self->parent_field_descriptor); } else { // The container has been released (i.e. by a call to Clear() or // ClearField() on the parent) and thus there's no message. @@ -225,19 +225,19 @@ static int UpdateChildMessages(RepeatedCompositeContainer* self) { const google::protobuf::Reflection* reflection = message->GetReflection(); for (Py_ssize_t i = child_length; i < message_length; ++i) { const Message& sub_message = reflection->GetRepeatedMessage( - *(self->message), self->parent_field->descriptor, i); - ScopedPyObjectPtr py_cmsg(cmessage::NewEmpty(self->subclass_init)); - if (py_cmsg == NULL) { + *(self->message), self->parent_field_descriptor, i); + CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, + sub_message.GetDescriptor()); + ScopedPyObjectPtr py_cmsg(reinterpret_cast(cmsg)); + if (cmsg == NULL) { return -1; } - CMessage* cmsg = reinterpret_cast(py_cmsg.get()); cmsg->owner = self->owner; cmsg->message = const_cast(&sub_message); cmsg->parent = self->parent; - if (cmessage::InitAttributes(cmsg, NULL, NULL) < 0) { + if (PyList_Append(self->child_messages, py_cmsg) < 0) { return -1; } - PyList_Append(self->child_messages, py_cmsg); } return 0; } @@ -258,23 +258,25 @@ static PyObject* AddToAttached(RepeatedCompositeContainer* self, google::protobuf::Message* message = self->message; google::protobuf::Message* sub_message = message->GetReflection()->AddMessage(message, - self->parent_field->descriptor); - PyObject* py_cmsg = cmessage::NewEmpty(self->subclass_init); - if (py_cmsg == NULL) { + self->parent_field_descriptor); + CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, + sub_message->GetDescriptor()); + if (cmsg == NULL) return NULL; - } - CMessage* cmsg = reinterpret_cast(py_cmsg); cmsg->owner = self->owner; cmsg->message = sub_message; cmsg->parent = self->parent; - // cmessage::InitAttributes must be called after cmsg->message has - // been set. - if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) { + if (cmessage::InitAttributes(cmsg, kwargs) < 0) { + Py_DECREF(cmsg); + return NULL; + } + + PyObject* py_cmsg = reinterpret_cast(cmsg); + if (PyList_Append(self->child_messages, py_cmsg) < 0) { Py_DECREF(py_cmsg); return NULL; } - PyList_Append(self->child_messages, py_cmsg); return py_cmsg; } @@ -283,20 +285,16 @@ static PyObject* AddToReleased(RepeatedCompositeContainer* self, PyObject* kwargs) { GOOGLE_CHECK_RELEASED(self); - // Create the CMessage - PyObject* py_cmsg = PyObject_CallObject(self->subclass_init, NULL); + // Create a new Message detached from the rest. + PyObject* py_cmsg = PyEval_CallObjectWithKeywords( + self->subclass_init, NULL, kwargs); if (py_cmsg == NULL) return NULL; - CMessage* cmsg = reinterpret_cast(py_cmsg); - if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) { + + if (PyList_Append(self->child_messages, py_cmsg) < 0) { Py_DECREF(py_cmsg); return NULL; } - - // The Message got created by the call to subclass_init above and - // it set self->owner to the newly allocated message. - - PyList_Append(self->child_messages, py_cmsg); return py_cmsg; } @@ -354,35 +352,9 @@ PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice) { if (UpdateChildMessages(self) < 0) { return NULL; } - Py_ssize_t from; - Py_ssize_t to; - Py_ssize_t step; - Py_ssize_t length = Length(self); - Py_ssize_t slicelength; - if (PySlice_Check(slice)) { -#if PY_MAJOR_VERSION >= 3 - if (PySlice_GetIndicesEx(slice, -#else - if (PySlice_GetIndicesEx(reinterpret_cast(slice), -#endif - length, &from, &to, &step, &slicelength) == -1) { - return NULL; - } - return PyList_GetSlice(self->child_messages, from, to); - } else if (PyInt_Check(slice) || PyLong_Check(slice)) { - from = to = PyLong_AsLong(slice); - if (from < 0) { - from = to = length + from; - } - PyObject* result = PyList_GetItem(self->child_messages, from); - if (result == NULL) { - return NULL; - } - Py_INCREF(result); - return result; - } - PyErr_SetString(PyExc_TypeError, "index must be an integer or slice"); - return NULL; + // Just forward the call to the subscript-handling function of the + // list containing the child messages. + return PyObject_GetItem(self->child_messages, slice); } int AssignSubscript(RepeatedCompositeContainer* self, @@ -399,7 +371,7 @@ int AssignSubscript(RepeatedCompositeContainer* self, // Delete from the underlying Message, if any. if (self->message != NULL) { if (cmessage::InternalDeleteRepeatedField(self->message, - self->parent_field->descriptor, + self->parent_field_descriptor, slice, self->child_messages) < 0) { return -1; @@ -512,7 +484,7 @@ static PyObject* SortAttached(RepeatedCompositeContainer* self, if (reverse) { google::protobuf::Message* message = self->message; const google::protobuf::Reflection* reflection = message->GetReflection(); - const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor; + const google::protobuf::FieldDescriptor* descriptor = self->parent_field_descriptor; // Reverse the Message array. for (int i = 0; i < length / 2; ++i) @@ -554,8 +526,9 @@ static PyObject* Sort(RepeatedCompositeContainer* self, } } - if (UpdateChildMessages(self) < 0) + if (UpdateChildMessages(self) < 0) { return NULL; + } if (self->message == NULL) { return SortReleased(self, args, kwds); } else { @@ -617,7 +590,7 @@ void ReleaseLastTo(const FieldDescriptor* field, shared_ptr released_message( ReleaseLast(field, cmessage->message->GetDescriptor(), message)); cmessage->parent = NULL; - cmessage->parent_field = NULL; + cmessage->parent_field_descriptor = NULL; cmessage->message = released_message.get(); cmessage->read_only = false; cmessage::SetOwner(cmessage, released_message); @@ -633,7 +606,7 @@ int Release(RepeatedCompositeContainer* self) { } Message* message = self->message; - const FieldDescriptor* field = self->parent_field->descriptor; + const FieldDescriptor* field = self->parent_field_descriptor; // The reflection API only lets us release the last message in a // repeated field. Therefore we iterate through the children @@ -648,7 +621,7 @@ int Release(RepeatedCompositeContainer* self) { // Detach from containing message. self->parent = NULL; - self->parent_field = NULL; + self->parent_field_descriptor = NULL; self->message = NULL; self->owner.reset(); @@ -670,22 +643,40 @@ int SetOwner(RepeatedCompositeContainer* self, return 0; } -static int Init(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwargs) { - self->message = NULL; - self->parent = NULL; - self->parent_field = NULL; - self->subclass_init = NULL; +// The private constructor of RepeatedCompositeContainer objects. +PyObject *NewContainer( + CMessage* parent, + const google::protobuf::FieldDescriptor* parent_field_descriptor, + PyObject *concrete_class) { + if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { + return NULL; + } + + RepeatedCompositeContainer* self = + reinterpret_cast( + PyType_GenericAlloc(&RepeatedCompositeContainer_Type, 0)); + if (self == NULL) { + return NULL; + } + + self->message = parent->message; + self->parent = parent; + self->parent_field_descriptor = parent_field_descriptor; + self->owner = parent->owner; + Py_INCREF(concrete_class); + self->subclass_init = concrete_class; self->child_messages = PyList_New(0); - return 0; + + return reinterpret_cast(self); } static void Dealloc(RepeatedCompositeContainer* self) { Py_CLEAR(self->child_messages); + Py_CLEAR(self->subclass_init); // TODO(tibell): Do we need to call delete on these objects to make // sure their destructors are called? self->owner.reset(); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); } @@ -755,7 +746,7 @@ PyTypeObject RepeatedCompositeContainer_Type = { 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset - (initproc)repeated_composite_container::Init, // tp_init + 0, // tp_init }; } // namespace python diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index 898ef5a7..a76a5d6a 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -55,7 +55,6 @@ using internal::shared_ptr; namespace python { struct CMessage; -struct CFieldDescriptor; // A RepeatedCompositeContainer can be in one of two states: attached // or released. @@ -66,7 +65,7 @@ struct CFieldDescriptor; // 'child_messages' are owner by the 'owner'. // // When in the released state 'message', 'owner', 'parent', and -// 'parent_field' are NULL. +// 'parent_field_descriptor' are NULL. typedef struct RepeatedCompositeContainer { PyObject_HEAD; @@ -82,7 +81,8 @@ typedef struct RepeatedCompositeContainer { CMessage* parent; // A descriptor used to modify the underlying 'message'. - CFieldDescriptor* parent_field; + // The pointer is owned by the global DescriptorPool. + const google::protobuf::FieldDescriptor* parent_field_descriptor; // Pointer to the C++ Message that contains this container. The // RepeatedCompositeContainer does not own this pointer. @@ -102,6 +102,13 @@ extern PyTypeObject RepeatedCompositeContainer_Type; namespace repeated_composite_container { +// Builds a RepeatedCompositeContainer object, from a parent message and a +// field descriptor. +PyObject *NewContainer( + CMessage* parent, + const google::protobuf::FieldDescriptor* parent_field_descriptor, + PyObject *concrete_class); + // Returns the number of items in this repeated composite container. static Py_ssize_t Length(RepeatedCompositeContainer* self); diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc index e627d37d..49d23fd6 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.cc +++ b/python/google/protobuf/pyext/repeated_scalar_container.cc @@ -52,7 +52,7 @@ #error "Python 3.0 - 3.2 are not supported." #else #define PyString_AsString(ob) \ - (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob)) + (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob)) #endif #endif @@ -67,7 +67,7 @@ namespace repeated_scalar_container { static int InternalAssignRepeatedField( RepeatedScalarContainer* self, PyObject* list) { self->message->GetReflection()->ClearField(self->message, - self->parent_field->descriptor); + self->parent_field_descriptor); for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) { PyObject* value = PyList_GET_ITEM(list, i); if (Append(self, value) == NULL) { @@ -80,7 +80,7 @@ static int InternalAssignRepeatedField( static Py_ssize_t Len(RepeatedScalarContainer* self) { google::protobuf::Message* message = self->message; return message->GetReflection()->FieldSize(*message, - self->parent_field->descriptor); + self->parent_field_descriptor); } static int AssignItem(RepeatedScalarContainer* self, @@ -89,12 +89,7 @@ static int AssignItem(RepeatedScalarContainer* self, cmessage::AssureWritable(self->parent); google::protobuf::Message* message = self->message; const google::protobuf::FieldDescriptor* field_descriptor = - self->parent_field->descriptor; - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); - return -1; - } + self->parent_field_descriptor; const google::protobuf::Reflection* reflection = message->GetReflection(); int field_size = reflection->FieldSize(*message, field_descriptor); @@ -175,7 +170,7 @@ static int AssignItem(RepeatedScalarContainer* self, ScopedPyObjectPtr s(PyObject_Str(arg)); if (s != NULL) { PyErr_Format(PyExc_ValueError, "Unknown enum value: %s", - PyString_AsString(s.get())); + PyString_AsString(s)); } return -1; } @@ -193,7 +188,7 @@ static int AssignItem(RepeatedScalarContainer* self, static PyObject* Item(RepeatedScalarContainer* self, Py_ssize_t index) { google::protobuf::Message* message = self->message; const google::protobuf::FieldDescriptor* field_descriptor = - self->parent_field->descriptor; + self->parent_field_descriptor; const google::protobuf::Reflection* reflection = message->GetReflection(); int field_size = reflection->FieldSize(*message, field_descriptor); @@ -358,13 +353,7 @@ PyObject* Append(RepeatedScalarContainer* self, PyObject* item) { cmessage::AssureWritable(self->parent); google::protobuf::Message* message = self->message; const google::protobuf::FieldDescriptor* field_descriptor = - self->parent_field->descriptor; - - if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); - return NULL; - } + self->parent_field_descriptor; const google::protobuf::Reflection* reflection = message->GetReflection(); switch (field_descriptor->cpp_type()) { @@ -422,7 +411,7 @@ PyObject* Append(RepeatedScalarContainer* self, PyObject* item) { ScopedPyObjectPtr s(PyObject_Str(item)); if (s != NULL) { PyErr_Format(PyExc_ValueError, "Unknown enum value: %s", - PyString_AsString(s.get())); + PyString_AsString(s)); } return NULL; } @@ -451,7 +440,7 @@ static int AssSubscript(RepeatedScalarContainer* self, cmessage::AssureWritable(self->parent); google::protobuf::Message* message = self->message; const google::protobuf::FieldDescriptor* field_descriptor = - self->parent_field->descriptor; + self->parent_field_descriptor; #if PY_MAJOR_VERSION < 3 if (PyInt_Check(slice)) { @@ -638,47 +627,25 @@ static PyObject* Sort(RepeatedScalarContainer* self, Py_RETURN_NONE; } -static int Init(RepeatedScalarContainer* self, - PyObject* args, - PyObject* kwargs) { - PyObject* py_parent; - PyObject* py_parent_field; - if (!PyArg_UnpackTuple(args, "__init__()", 2, 2, &py_parent, - &py_parent_field)) { - return -1; - } - - if (!PyObject_TypeCheck(py_parent, &CMessage_Type)) { - PyErr_Format(PyExc_TypeError, - "expect %s, but got %s", - CMessage_Type.tp_name, - Py_TYPE(py_parent)->tp_name); - return -1; +// The private constructor of RepeatedScalarContainer objects. +PyObject *NewContainer( + CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) { + if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { + return NULL; } - if (!PyObject_TypeCheck(py_parent_field, &CFieldDescriptor_Type)) { - PyErr_Format(PyExc_TypeError, - "expect %s, but got %s", - CFieldDescriptor_Type.tp_name, - Py_TYPE(py_parent_field)->tp_name); - return -1; + RepeatedScalarContainer* self = reinterpret_cast( + PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0)); + if (self == NULL) { + return NULL; } - CMessage* cmessage = reinterpret_cast(py_parent); - CFieldDescriptor* cdescriptor = reinterpret_cast( - py_parent_field); - - if (!FIELD_BELONGS_TO_MESSAGE(cdescriptor->descriptor, cmessage->message)) { - PyErr_SetString( - PyExc_KeyError, "Field does not belong to message!"); - return -1; - } + self->message = parent->message; + self->parent = parent; + self->parent_field_descriptor = parent_field_descriptor; + self->owner = parent->owner; - self->message = cmessage->message; - self->parent = cmessage; - self->parent_field = cdescriptor; - self->owner = cmessage->owner; - return 0; + return reinterpret_cast(self); } // Initializes the underlying Message object of "to" so it becomes a new parent @@ -699,10 +666,7 @@ static int InitializeAndCopyToParentContainer( google::protobuf::Message* new_message = global_message_factory->GetPrototype( from->message->GetDescriptor())->New(); to->parent = NULL; - // TODO(anuraag): Document why it's OK to hang on to parent_field, - // even though it's a weak reference. It ought to be enough to - // hold on to the FieldDescriptor only. - to->parent_field = from->parent_field; + to->parent_field_descriptor = from->parent_field_descriptor; to->message = new_message; to->owner.reset(new_message); if (InternalAssignRepeatedField(to, values) < 0) { @@ -716,23 +680,17 @@ int Release(RepeatedScalarContainer* self) { } PyObject* DeepCopy(RepeatedScalarContainer* self, PyObject* arg) { - ScopedPyObjectPtr init_args( - PyTuple_Pack(2, self->parent, self->parent_field)); - PyObject* clone = PyObject_CallObject( - reinterpret_cast(&RepeatedScalarContainer_Type), init_args); + RepeatedScalarContainer* clone = reinterpret_cast( + PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0)); if (clone == NULL) { return NULL; } - if (!PyObject_TypeCheck(clone, &RepeatedScalarContainer_Type)) { - Py_DECREF(clone); - return NULL; - } - if (InitializeAndCopyToParentContainer( - self, reinterpret_cast(clone)) < 0) { + + if (InitializeAndCopyToParentContainer(self, clone) < 0) { Py_DECREF(clone); return NULL; } - return clone; + return reinterpret_cast(clone); } static void Dealloc(RepeatedScalarContainer* self) { @@ -817,7 +775,7 @@ PyTypeObject RepeatedScalarContainer_Type = { 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset - (initproc)repeated_scalar_container::Init, // tp_init + 0, // tp_init }; } // namespace python diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h index 69d15d5c..513bfe48 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.h +++ b/python/google/protobuf/pyext/repeated_scalar_container.h @@ -41,6 +41,7 @@ #include #endif +#include namespace google { namespace protobuf { @@ -51,7 +52,6 @@ using internal::shared_ptr; namespace python { -struct CFieldDescriptor; struct CMessage; typedef struct RepeatedScalarContainer { @@ -73,16 +73,22 @@ typedef struct RepeatedScalarContainer { // modifying the container. CMessage* parent; - // Weak reference to the parent's descriptor that describes this + // Pointer to the parent's descriptor that describes this // field. Used together with the parent's message when making a // default message instance mutable. - CFieldDescriptor* parent_field; + // The pointer is owned by the global DescriptorPool. + const google::protobuf::FieldDescriptor* parent_field_descriptor; } RepeatedScalarContainer; extern PyTypeObject RepeatedScalarContainer_Type; namespace repeated_scalar_container { +// Builds a RepeatedScalarContainer object, from a parent message and a +// field descriptor. +extern PyObject *NewContainer( + CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor); + // Appends the scalar 'item' to the end of the container 'self'. // // Returns None if successful; returns NULL and sets an exception if diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h index 9f337c3c..fefebb6a 100644 --- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h +++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h @@ -33,6 +33,8 @@ #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__ #define GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__ +#include + #include namespace google { diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index 2429fa59..b2f3d32c 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -112,15 +112,17 @@ def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False, for element in value: PrintField(field, element, out, indent, as_utf8, as_one_line, pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) else: PrintField(field, value, out, indent, as_utf8, as_one_line, pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False, - pointy_brackets=False, float_format=None): + pointy_brackets=False, use_index_order=False, float_format=None): """Print a single field name/value pair. For repeated fields, the value should be a single element.""" @@ -148,6 +150,7 @@ def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False, PrintFieldValue(field, value, out, indent, as_utf8, as_one_line, pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) if as_one_line: out.write(' ') @@ -157,6 +160,7 @@ def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False, def PrintFieldValue(field, value, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, + use_index_order=False, float_format=None): """Print a single field value (not including name). For repeated fields, the value should be a single element.""" @@ -173,12 +177,14 @@ def PrintFieldValue(field, value, out, indent=0, as_utf8=False, out.write(' %s ' % openb) PrintMessage(value, out, indent, as_utf8, as_one_line, pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) out.write(closeb) else: out.write(' %s\n' % openb) PrintMessage(value, out, indent + 2, as_utf8, as_one_line, pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) out.write(' ' * indent + closeb) elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: diff --git a/python/setup.py b/python/setup.py index 22a2c98f..7337260a 100755 --- a/python/setup.py +++ b/python/setup.py @@ -86,6 +86,8 @@ def GenerateUnittestProtos(): generate_proto("google/protobuf/internal/more_messages.proto") generate_proto("google/protobuf/internal/factory_test1.proto") generate_proto("google/protobuf/internal/factory_test2.proto") + generate_proto("google/protobuf/internal/import_test_package/inner.proto") + generate_proto("google/protobuf/internal/import_test_package/outer.proto") generate_proto("google/protobuf/pyext/python.proto") def MakeTestSuite(): @@ -185,6 +187,7 @@ if __name__ == '__main__': 'google.protobuf.descriptor_database', 'google.protobuf.descriptor_pool', 'google.protobuf.message_factory', + 'google.protobuf.proto_builder', 'google.protobuf.pyext.cpp_message', 'google.protobuf.reflection', 'google.protobuf.service', diff --git a/src/Makefile.am b/src/Makefile.am index 2e22b020..a111e14c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,6 +38,7 @@ MAINTAINERCLEANFILES = \ Makefile.in nobase_include_HEADERS = \ + google/protobuf/stubs/atomic_sequence_num.h \ google/protobuf/stubs/atomicops.h \ google/protobuf/stubs/atomicops_internals_arm64_gcc.h \ google/protobuf/stubs/atomicops_internals_arm_gcc.h \ @@ -51,24 +52,32 @@ nobase_include_HEADERS = \ google/protobuf/stubs/atomicops_internals_tsan.h \ google/protobuf/stubs/atomicops_internals_x86_gcc.h \ google/protobuf/stubs/atomicops_internals_x86_msvc.h \ + google/protobuf/stubs/casts.h \ + google/protobuf/stubs/singleton.h \ google/protobuf/stubs/common.h \ - google/protobuf/stubs/platform_macros.h \ + google/protobuf/stubs/fastmem.h \ google/protobuf/stubs/once.h \ + google/protobuf/stubs/platform_macros.h \ google/protobuf/stubs/stl_util.h \ google/protobuf/stubs/template_util.h \ google/protobuf/stubs/type_traits.h \ + google/protobuf/arena.h \ + google/protobuf/arenastring.h \ + google/protobuf/descriptor_database.h \ google/protobuf/descriptor.h \ google/protobuf/descriptor.pb.h \ - google/protobuf/descriptor_database.h \ google/protobuf/dynamic_message.h \ google/protobuf/extension_set.h \ google/protobuf/generated_enum_reflection.h \ - google/protobuf/generated_message_util.h \ google/protobuf/generated_message_reflection.h \ + google/protobuf/generated_message_util.h \ google/protobuf/message.h \ google/protobuf/message_lite.h \ + google/protobuf/metadata.h \ + google/protobuf/reflection.h \ google/protobuf/reflection_ops.h \ google/protobuf/repeated_field.h \ + google/protobuf/repeated_field_reflection.h \ google/protobuf/service.h \ google/protobuf/text_format.h \ google/protobuf/unknown_field_set.h \ @@ -107,6 +116,8 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/stubs/shared_ptr.h \ google/protobuf/stubs/stringprintf.cc \ google/protobuf/stubs/stringprintf.h \ + google/protobuf/arena.cc \ + google/protobuf/arenastring.cc \ google/protobuf/extension_set.cc \ google/protobuf/generated_message_util.cc \ google/protobuf/message_lite.cc \ @@ -127,12 +138,13 @@ libprotobuf_la_SOURCES = \ google/protobuf/stubs/substitute.h \ google/protobuf/stubs/structurally_valid.cc \ google/protobuf/descriptor.cc \ - google/protobuf/descriptor.pb.cc \ google/protobuf/descriptor_database.cc \ + google/protobuf/descriptor.pb.cc \ google/protobuf/dynamic_message.cc \ google/protobuf/extension_set_heavy.cc \ google/protobuf/generated_message_reflection.cc \ google/protobuf/message.cc \ + google/protobuf/reflection_internal.h \ google/protobuf/reflection_ops.cc \ google/protobuf/service.cc \ google/protobuf/text_format.cc \ @@ -184,9 +196,9 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_context.cc \ google/protobuf/compiler/java/java_context.h \ google/protobuf/compiler/java/java_enum.cc \ - google/protobuf/compiler/java/java_enum.h \ google/protobuf/compiler/java/java_enum_field.cc \ google/protobuf/compiler/java/java_enum_field.h \ + google/protobuf/compiler/java/java_enum.h \ google/protobuf/compiler/java/java_extension.cc \ google/protobuf/compiler/java/java_extension.h \ google/protobuf/compiler/java/java_field.cc \ @@ -200,10 +212,12 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_helpers.h \ google/protobuf/compiler/java/java_lazy_message_field.cc \ google/protobuf/compiler/java/java_lazy_message_field.h \ + google/protobuf/compiler/java/java_map_field.cc \ + google/protobuf/compiler/java/java_map_field.h \ google/protobuf/compiler/java/java_message.cc \ - google/protobuf/compiler/java/java_message.h \ google/protobuf/compiler/java/java_message_field.cc \ google/protobuf/compiler/java/java_message_field.h \ + google/protobuf/compiler/java/java_message.h \ google/protobuf/compiler/java/java_name_resolver.cc \ google/protobuf/compiler/java/java_name_resolver.h \ google/protobuf/compiler/java/java_primitive_field.cc \ @@ -226,18 +240,25 @@ protoc_SOURCES = google/protobuf/compiler/main.cc protoc_inputs = \ google/protobuf/unittest.proto \ - google/protobuf/unittest_empty.proto \ - google/protobuf/unittest_import.proto \ - google/protobuf/unittest_import_public.proto \ - google/protobuf/unittest_mset.proto \ - google/protobuf/unittest_optimize_for.proto \ - google/protobuf/unittest_embed_optimize_for.proto \ + google/protobuf/unittest_arena.proto \ google/protobuf/unittest_custom_options.proto \ - google/protobuf/unittest_lite.proto \ + google/protobuf/unittest_drop_unknown_fields.proto \ + google/protobuf/unittest_embed_optimize_for.proto \ + google/protobuf/unittest_empty.proto \ google/protobuf/unittest_import_lite.proto \ + google/protobuf/unittest_import.proto \ google/protobuf/unittest_import_public_lite.proto \ + google/protobuf/unittest_import_public.proto \ google/protobuf/unittest_lite_imports_nonlite.proto \ + google/protobuf/unittest_lite.proto \ + google/protobuf/unittest_mset.proto \ + google/protobuf/unittest_no_arena_import.proto \ + google/protobuf/unittest_no_arena.proto \ + google/protobuf/unittest_no_field_presence.proto \ google/protobuf/unittest_no_generic_services.proto \ + google/protobuf/unittest_optimize_for.proto \ + google/protobuf/unittest_preserve_unknown_enum.proto \ + google/protobuf/unittest_proto3_arena.proto \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto EXTRA_DIST = \ @@ -273,24 +294,38 @@ protoc_outputs = \ $(protoc_lite_outputs) \ google/protobuf/unittest.pb.cc \ google/protobuf/unittest.pb.h \ + google/protobuf/unittest_arena.pb.cc \ + google/protobuf/unittest_arena.pb.h \ + google/protobuf/unittest_custom_options.pb.cc \ + google/protobuf/unittest_custom_options.pb.h \ + google/protobuf/unittest_drop_unknown_fields.pb.cc \ + google/protobuf/unittest_drop_unknown_fields.pb.h \ + google/protobuf/unittest_embed_optimize_for.pb.cc \ + google/protobuf/unittest_embed_optimize_for.pb.h \ google/protobuf/unittest_empty.pb.cc \ google/protobuf/unittest_empty.pb.h \ google/protobuf/unittest_import.pb.cc \ google/protobuf/unittest_import.pb.h \ google/protobuf/unittest_import_public.pb.cc \ google/protobuf/unittest_import_public.pb.h \ - google/protobuf/unittest_mset.pb.cc \ - google/protobuf/unittest_mset.pb.h \ - google/protobuf/unittest_optimize_for.pb.cc \ - google/protobuf/unittest_optimize_for.pb.h \ - google/protobuf/unittest_embed_optimize_for.pb.cc \ - google/protobuf/unittest_embed_optimize_for.pb.h \ - google/protobuf/unittest_custom_options.pb.cc \ - google/protobuf/unittest_custom_options.pb.h \ google/protobuf/unittest_lite_imports_nonlite.pb.cc \ google/protobuf/unittest_lite_imports_nonlite.pb.h \ + google/protobuf/unittest_mset.pb.cc \ + google/protobuf/unittest_mset.pb.h \ + google/protobuf/unittest_no_arena.pb.cc \ + google/protobuf/unittest_no_arena.pb.h \ + google/protobuf/unittest_no_arena_import.pb.cc \ + google/protobuf/unittest_no_arena_import.pb.h \ + google/protobuf/unittest_no_field_presence.pb.cc \ + google/protobuf/unittest_no_field_presence.pb.h \ google/protobuf/unittest_no_generic_services.pb.cc \ google/protobuf/unittest_no_generic_services.pb.h \ + google/protobuf/unittest_optimize_for.pb.cc \ + google/protobuf/unittest_optimize_for.pb.h \ + google/protobuf/unittest_preserve_unknown_enum.pb.cc \ + google/protobuf/unittest_preserve_unknown_enum.pb.h \ + google/protobuf/unittest_proto3_arena.pb.cc \ + google/protobuf/unittest_proto3_arena.pb.h \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h @@ -342,15 +377,21 @@ protobuf_test_SOURCES = \ google/protobuf/stubs/stringprintf_unittest.cc \ google/protobuf/stubs/template_util_unittest.cc \ google/protobuf/stubs/type_traits_unittest.cc \ + google/protobuf/arenastring_unittest.cc \ + google/protobuf/arena_unittest.cc \ google/protobuf/descriptor_database_unittest.cc \ google/protobuf/descriptor_unittest.cc \ + google/protobuf/drop_unknown_fields_test.cc \ google/protobuf/dynamic_message_unittest.cc \ google/protobuf/extension_set_unittest.cc \ google/protobuf/generated_message_reflection_unittest.cc \ google/protobuf/message_unittest.cc \ + google/protobuf/no_field_presence_test.cc \ + google/protobuf/preserve_unknown_enum_test.cc \ + google/protobuf/proto3_arena_unittest.cc \ google/protobuf/reflection_ops_unittest.cc \ - google/protobuf/repeated_field_unittest.cc \ google/protobuf/repeated_field_reflection_unittest.cc \ + google/protobuf/repeated_field_unittest.cc \ google/protobuf/text_format_unittest.cc \ google/protobuf/unknown_field_set_unittest.cc \ google/protobuf/wire_format_unittest.cc \ diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc new file mode 100644 index 00000000..59863986 --- /dev/null +++ b/src/google/protobuf/arena.cc @@ -0,0 +1,238 @@ +// 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 + +namespace google { +namespace protobuf { + +google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_; +__thread Arena::ThreadCache Arena::thread_cache_ = { -1, NULL }; + +void Arena::Init(const ArenaOptions& options) { + lifecycle_id_ = lifecycle_id_generator_.GetNext(); + start_block_size_ = options.start_block_size; + max_block_size_ = options.max_block_size; + block_alloc = options.block_alloc; + block_dealloc = options.block_dealloc; + blocks_ = NULL; + hint_ = NULL; + owns_first_block_ = true; + cleanup_list_ = NULL; + + if (options.initial_block != NULL && options.initial_block_size > 0) { + // Add first unowned block to list. + Block* first_block = reinterpret_cast(options.initial_block); + first_block->size = options.initial_block_size; + first_block->pos = kHeaderSize; + first_block->next = NULL; + first_block->owner = &first_block->owner; + AddBlock(first_block); + owns_first_block_ = false; + } +} + +uint64 Arena::Reset() { + CleanupList(); + uint64 space_used = FreeBlocks(); + // Invalidate any ThreadCaches pointing to any blocks we just destroyed. + lifecycle_id_ = lifecycle_id_generator_.GetNext(); + return space_used; +} + +Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n, + size_t start_block_size, size_t max_block_size) { + size_t size; + if (my_last_block != NULL) { + // Double the current block size, up to a limit. + size = 2 * (my_last_block->size); + if (size > max_block_size) size = max_block_size; + } else { + size = start_block_size; + } + if (n > size - kHeaderSize) { + // TODO(sanjay): Check if n + kHeaderSize would overflow + size = kHeaderSize + n; + } + + Block* b = reinterpret_cast(block_alloc(size)); + b->pos = kHeaderSize + n; + b->size = size; + if (b->avail() == 0) { + // Do not attempt to reuse this block. + b->owner = NULL; + } else { + b->owner = me; + } + return b; +} + +void Arena::AddBlock(Block* b) { + MutexLock l(&blocks_lock_); + b->next = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); + google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast(b)); + if (b->avail() != 0) { + // Direct future allocations to this block. + google::protobuf::internal::Release_Store(&hint_, reinterpret_cast(b)); + } +} + +void Arena::AddListNode(void* elem, void (*cleanup)(void*)) { + Node* node = reinterpret_cast(AllocateAligned(sizeof(Node))); + node->elem = elem; + node->cleanup = cleanup; + node->next = reinterpret_cast( + google::protobuf::internal::NoBarrier_AtomicExchange(&cleanup_list_, + reinterpret_cast(node))); +} + +void* Arena::AllocateAligned(size_t n) { + // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.) + n = (n + 7) & -8; + + // If this thread already owns a block in this arena then try to use that. + // This fast path optimizes the case where multiple threads allocate from the + // same arena. + if (thread_cache_.last_lifecycle_id_seen == lifecycle_id_ && + thread_cache_.last_block_used_ != NULL) { + if (thread_cache_.last_block_used_->avail() < n) { + return SlowAlloc(n); + } + return AllocFromBlock(thread_cache_.last_block_used_, n); + } + + // Check whether we own the last accessed block on this arena. + // This fast path optimizes the case where a single thread uses multiple + // arenas. + void* me = &thread_cache_; + Block* b = reinterpret_cast(google::protobuf::internal::Acquire_Load(&hint_)); + if (!b || b->owner != me || b->avail() < n) { + // If the next block to allocate from is the first block, try to claim it + // for this thread. + if (!owns_first_block_ && b->next == NULL) { + MutexLock l(&blocks_lock_); + if (b->owner == &b->owner) { + b->owner = me; + SetThreadCacheBlock(b); + return AllocFromBlock(b, n); + } + } + return SlowAlloc(n); + } + return AllocFromBlock(b, n); +} + +void* Arena::AllocFromBlock(Block* b, size_t n) { + size_t p = b->pos; + b->pos = p + n; + return reinterpret_cast(b) + p; +} + +void* Arena::SlowAlloc(size_t n) { + void* me = &thread_cache_; + Block* b = FindBlock(me); // Find block owned by me. + // See if allocation fits in my latest block. + if (b != NULL && b->avail() >= n) { + SetThreadCacheBlock(b); + google::protobuf::internal::NoBarrier_Store(&hint_, reinterpret_cast(b)); + return AllocFromBlock(b, n); + } + b = NewBlock(me, b, n, start_block_size_, max_block_size_); + AddBlock(b); + if (b->owner == me) { // If this block can be reused (see NewBlock()). + SetThreadCacheBlock(b); + } + return reinterpret_cast(b) + kHeaderSize; +} + +uint64 Arena::SpaceUsed() const { + uint64 space_used = 0; + Block* b = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); + while (b != NULL) { + space_used += (b->size); + b = b->next; + } + return space_used; +} + + +uint64 Arena::FreeBlocks() { + uint64 space_used = 0; + Block* b = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); + Block* first_block = NULL; + while (b != NULL) { + space_used += (b->size); + Block* next = b->next; + if (next != NULL) { + block_dealloc(b, b->size); + } else { + if (owns_first_block_) { + block_dealloc(b, b->size); + } else { + // User passed in the first block, skip free'ing the memory. + first_block = b; + } + } + b = next; + } + blocks_ = 0; + hint_ = 0; + if (!owns_first_block_) { + // Make the first block that was passed in through ArenaOptions + // available for reuse. + first_block->pos = kHeaderSize; + first_block->owner = &first_block->owner; + AddBlock(first_block); + } + return space_used; +} + +void Arena::CleanupList() { + Node* head = + reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&cleanup_list_)); + while (head != NULL) { + head->cleanup(head->elem); + head = head->next; + } + cleanup_list_ = 0; +} + +Arena::Block* Arena::FindBlock(void* me) { + // TODO(sanjay): We might want to keep a separate list with one + // entry per thread. + Block* b = reinterpret_cast(google::protobuf::internal::Acquire_Load(&blocks_)); + while (b != NULL && b->owner != me) { + b = b->next; + } + return b; +} + +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h new file mode 100644 index 00000000..519e3569 --- /dev/null +++ b/src/google/protobuf/arena.h @@ -0,0 +1,479 @@ +// 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. + +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_ARENA_H__ +#define GOOGLE_PROTOBUF_ARENA_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +class Arena; // defined below +class Message; // message.h + +namespace internal { +class ArenaString; // arenastring.h +class LazyField; // lazy_field.h + +template +class GenericTypeHandler; // repeated_field.h + +// Templated cleanup methods. +template void arena_destruct_object(void* object) { + reinterpret_cast(object)->~T(); +} +template void arena_delete_object(void* object) { + delete reinterpret_cast(object); +} +inline void arena_free(void* object, size_t size) { + free(object); +} + +} // namespace internal + +// ArenaOptions provides optional additional parameters to arena construction +// that control its block-allocation behavior. +struct ArenaOptions { + // This defines the size of the first block requested from the system malloc. + // Subsequent block sizes will increase in a geometric series up to a maximum. + size_t start_block_size; + + // This defines the maximum block size requested from system malloc (unless an + // individual arena allocation request occurs with a size larger than this + // maximum). Requested block sizes increase up to this value, then remain + // here. + size_t max_block_size; + + // An initial block of memory for the arena to use, or NULL for none. If + // provided, the block must live at least as long as the arena itself. The + // creator of the Arena retains ownership of the block after the Arena is + // destroyed. + char* initial_block; + + // The size of the initial block, if provided. + size_t initial_block_size; + + // A function pointer to an alloc method that returns memory blocks of size + // requested. By default, it contains a ptr to the malloc function. + void* (*block_alloc)(size_t); + // A function pointer to a dealloc method that takes ownership of the blocks + // from the arena. By default, it contains a ptr to a wrapper function that + // calls free. + void (*block_dealloc)(void*, size_t); + + ArenaOptions() + : start_block_size(kDefaultStartBlockSize), + max_block_size(kDefaultMaxBlockSize), + initial_block(NULL), + initial_block_size(0), + block_alloc(&malloc), + block_dealloc(&internal::arena_free) {} + + private: + // Constants define default starting block size and max block size for + // arena allocator behavior -- see descriptions above. + static const size_t kDefaultStartBlockSize = 256; + static const size_t kDefaultMaxBlockSize = 8192; +}; + +// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation +// with new/delete, and improves performance by aggregating allocations into +// larger blocks and freeing allocations all at once. Protocol messages are +// allocated on an arena by using Arena::CreateMessage(Arena*), below, and +// are automatically freed when the arena is destroyed. +// +// This is a thread-safe implementation: multiple threads may allocate from the +// arena concurrently. Destruction is not thread-safe and the destructing +// thread must synchronize with users of the arena first. +class LIBPROTOBUF_EXPORT Arena { + public: + // Arena constructor taking custom options. See ArenaOptions below for + // descriptions of the options available. + explicit Arena(const ArenaOptions& options) { + Init(options); + } + + // Default constructor with sensible default options, tuned for average + // use-cases. + Arena() { + Init(ArenaOptions()); + } + + // Destructor deletes all owned heap allocated objects, and destructs objects + // that have non-trivial destructors, except for proto2 message objects whose + // destructors can be skipped. Also, frees all blocks except the initial block + // if it was passed in. + ~Arena() { + Reset(); + } + + // API to create proto2 message objects on the arena. If the arena passed in + // is NULL, then a heap allocated object is returned. Type T must be a message + // defined in a .proto file with cc_enable_arenas set to true, otherwise a + // compilation error will occur. + // + // RepeatedField and RepeatedPtrField may also be instantiated directly on an + // arena with this method: they act as "arena-capable message types" for the + // purposes of the Arena API. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* CreateMessage(::google::protobuf::Arena* arena) { + if (arena == NULL) { + return new T; + } else { + return arena->CreateMessageInternal(static_cast(0)); + } + } + + // API to create any objects on the arena. Note that only the object will + // be created on the arena; the underlying ptrs (in case of a proto2 message) + // will be still heap allocated. Proto messages should usually be allocated + // with CreateMessage() instead. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* Create(::google::protobuf::Arena* arena) { + if (arena == NULL) { + return new T(); + } else { + return arena->CreateInternal( + SkipDeleteList(static_cast(0))); + } + } + + // Version of the above with one constructor argument for the created object. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* Create(::google::protobuf::Arena* arena, const Arg& arg) { + if (arena == NULL) { + return new T(arg); + } else { + return arena->CreateInternal(SkipDeleteList(static_cast(0)), + arg); + } + } + + // Version of the above with two constructor arguments for the created object. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* Create(::google::protobuf::Arena* arena, const Arg1& arg1, const Arg2& arg2) { + if (arena == NULL) { + return new T(arg1, arg2); + } else { + return arena->CreateInternal(SkipDeleteList(static_cast(0)), + arg1, + arg2); + } + } + + // Create an array of object type T on the arena. Type T must have a trivial + // constructor, as it will not be invoked when created on the arena. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) { + if (arena == NULL) { + return new T[num_elements]; + } else { + return static_cast( + arena->AllocateAligned(num_elements * sizeof(T))); + } + } + + // Returns the total space used by the arena, which is the sums of the sizes + // of the underlying blocks. The total space used may not include the new + // blocks that are allocated by this arena from other threads concurrently + // with the call to this method. + uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE; + + // Frees all storage allocated by this arena after calling destructors + // registered with OwnDestructor() and freeing objects registered with Own(). + // Any objects allocated on this arena are unusable after this call. It also + // returns the total space used by the arena which is the sums of the sizes + // of the allocated blocks. This method is not thread-safe. + uint64 Reset() GOOGLE_ATTRIBUTE_NOINLINE; + + // Adds |object| to a list of heap-allocated objects to be freed with |delete| + // when the arena is destroyed or reset. + template GOOGLE_ATTRIBUTE_NOINLINE + void Own(T* object) { + OwnInternal(object, google::protobuf::internal::is_convertible()); + } + + // Adds |object| to a list of objects whose destructors will be manually + // called when the arena is destroyed or reset. This differs from Own() in + // that it does not free the underlying memory with |delete|; hence, it is + // normally only used for objects that are placement-newed into + // arena-allocated memory. + template GOOGLE_ATTRIBUTE_NOINLINE + void OwnDestructor(T* object) { + if (object != NULL) { + AddListNode(object, &internal::arena_destruct_object); + } + } + + // Adds a custom member function on an object to the list of destructors that + // will be manually called when the arena is destroyed or reset. This differs + // from OwnDestructor() in that any member function may be specified, not only + // the class destructor. + void OwnCustomDestructor(void* object, void (*destruct)(void*)) + GOOGLE_ATTRIBUTE_NOINLINE { + AddListNode(object, destruct); + } + + // Retrieves the arena associated with |value| if |value| is an arena-capable + // message, or NULL otherwise. This differs from value->GetArena() in that the + // latter is a virtual call, while this method is a templated call that + // resolves at compile-time. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static inline ::google::protobuf::Arena* GetArena(T* value) { + return GetArenaInternal(value, static_cast(0)); + } + + // Helper typetrait that indicates support for arenas in a type T at compile + // time. This is public only to allow construction of higher-level templated + // utilities. is_arena_constructable::value is an instance of + // google::protobuf::internal::true_type if the message type T has arena support enabled, and + // google::protobuf::internal::false_type otherwise. + // + // This is inside Arena because only Arena has the friend relationships + // necessary to see the underlying generated code traits. + template + struct is_arena_constructable { + template + static char ArenaConstructable( + const typename U::InternalArenaConstructable_*); + template + static double ArenaConstructable(...); + + // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. + typedef google::protobuf::internal::integral_constant(static_cast(0))) == + sizeof(char)> type; + static const type value; + }; + + private: + // Blocks are variable length malloc-ed objects. The following structure + // describes the common header for all blocks. + struct Block { + void* owner; // &ThreadCache of thread that owns this block, or + // &this->owner if not yet owned by a thread. + Block* next; // Next block in arena (may have different owner) + // ((char*) &block) + pos is next available byte. It is always + // aligned at a multiple of 8 bytes. + size_t pos; + size_t size; // total size of the block. + size_t avail() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { return size - pos; } + // data follows + }; + + void* (*block_alloc)(size_t); // Allocates a free block of a particular size. + void (*block_dealloc)(void*, size_t); // Deallocates the given block. + + template friend class ::google::protobuf::internal::GenericTypeHandler; + friend class MockArena; // For unit-testing. + friend class internal::ArenaString; // For AllocateAligned. + friend class internal::LazyField; // For CreateMaybeMessage. + + struct ThreadCache { + // The ThreadCache is considered valid as long as this matches the + // lifecycle_id of the arena being used. + int64 last_lifecycle_id_seen; + Block* last_block_used_; + }; + + static const size_t kHeaderSize = sizeof(Block); + static google::protobuf::internal::SequenceNumber lifecycle_id_generator_; + static __thread ThreadCache thread_cache_; + + // SFINAE for skipping addition to delete list for a Type. This is mainly to + // skip proto2/proto1 message objects with cc_enable_arenas=true from being + // part of the delete list. Also, note, compiler will optimize out the branch + // in CreateInternal. + // + template + static inline bool SkipDeleteList(typename T::DestructorSkippable_*) { + return true; + } + + // For non message objects, we skip addition to delete list if the object has + // a trivial destructor. + template + static inline bool SkipDeleteList(...) { + return google::protobuf::internal::has_trivial_destructor::value; + } + + // CreateMessage requires that T supports arenas, but this private method + // works whether or not T supports arenas. These are not exposed to user code + // as it can cause confusing API usages, and end up having double free in + // user code. These are used only internally from LazyField and Repeated + // fields, since they are designed to work in all mode combinations. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static Msg* CreateMaybeMessage( + Arena* arena, typename Msg::InternalArenaConstructable_*) { + return CreateMessage(arena); + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* CreateMaybeMessage(Arena* arena, ...) { + return Create(arena); + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateInternal( + bool skip_explicit_ownership) { + T* t = new (AllocateAligned(sizeof(T))) T(); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateInternal( + bool skip_explicit_ownership, const Arg& arg) { + T* t = new (AllocateAligned(sizeof(T))) T(arg); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateInternal( + bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) { + T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) { + return CreateInternal(SkipDeleteList(static_cast(0)), + this); + } + + // These implement Own(), which registers an object for deletion (destructor + // call and operator delete()). The second parameter has type 'true_type' if T + // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing + // all template instantiations to one for generic Message reduces code size, + // using the virtual destructor instead. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + void OwnInternal(T* object, google::protobuf::internal::true_type) { + if (object != NULL) { + AddListNode(object, &internal::arena_delete_object< ::google::protobuf::Message >); + } + } + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + void OwnInternal(T* object, google::protobuf::internal::false_type) { + if (object != NULL) { + AddListNode(object, &internal::arena_delete_object); + } + } + + // Implementation for GetArena(). Only message objects with + // InternalArenaConstructable_ tags can be associated with an arena, and such + // objects must implement a GetArenaNoVirtual() method. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static inline ::google::protobuf::Arena* GetArenaInternal(T* value, + typename T::InternalArenaConstructable_*) { + return value->GetArenaNoVirtual(); + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static inline ::google::protobuf::Arena* GetArenaInternal(T* value, ...) { + return NULL; + } + + + void* AllocateAligned(size_t size); + + void Init(const ArenaOptions& options); + + // Free all blocks and return the total space used which is the sums of sizes + // of the all the allocated blocks. + uint64 FreeBlocks(); + + // Add object pointer and cleanup function pointer to the list. + // TODO(rohananil, cfallin): We could pass in a sub-arena into this method + // to avoid polluting blocks of this arena with list nodes. This would help in + // mixed mode (where many protobufs have cc_enable_arenas=false), and is an + // alternative to a chunked linked-list, but with extra overhead of *next. + void AddListNode(void* elem, void (*cleanup)(void*)); + // Delete or Destruct all objects owned by the arena. + void CleanupList(); + + inline void SetThreadCacheBlock(Block* block) { + thread_cache_.last_block_used_ = block; + thread_cache_.last_lifecycle_id_seen = lifecycle_id_; + } + + int64 lifecycle_id_; // Unique for each arena. Changes on Reset(). + size_t start_block_size_; // Starting block size of the arena. + size_t max_block_size_; // Max block size of the arena. + + google::protobuf::internal::AtomicWord blocks_; // Head of linked list of all allocated blocks + google::protobuf::internal::AtomicWord hint_; // Fast thread-local block access + + // Node contains the ptr of the object to be cleaned up and the associated + // cleanup function ptr. + struct Node { + void* elem; // Pointer to the object to be cleaned up. + void (*cleanup)(void*); // Function pointer to the destructor or deleter. + Node* next; // Next node in the list. + }; + + google::protobuf::internal::AtomicWord cleanup_list_; // Head of a linked list of nodes containing object + // ptrs and cleanup methods. + + bool owns_first_block_; // Indicates that arena owns the first block + Mutex blocks_lock_; + + void AddBlock(Block* b); + void* SlowAlloc(size_t n); + Block* FindBlock(void* me); + Block* NewBlock(void* me, Block* my_last_block, size_t n, + size_t start_block_size, size_t max_block_size); + static void* AllocFromBlock(Block* b, size_t n); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena); +}; + +template +const typename Arena::is_arena_constructable::type + Arena::is_arena_constructable::value = + typename Arena::is_arena_constructable::type(); + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_ARENA_H__ diff --git a/src/google/protobuf/arena_nc.cc b/src/google/protobuf/arena_nc.cc new file mode 100644 index 00000000..f2f08427 --- /dev/null +++ b/src/google/protobuf/arena_nc.cc @@ -0,0 +1,45 @@ +// 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. + +// Negative compilation test for arena usage. + +#include +#include + +#ifdef TEST_ARENA_PRIVATE_CONSTRUCTOR + +namespace google { +void ArenaPrivateConstructor() { + google::protobuf::Arena arena; + protobuf_unittest::TestAllTypes message(&arena); +} + +#endif +} // namespace google diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py new file mode 100644 index 00000000..41b1b5f8 --- /dev/null +++ b/src/google/protobuf/arena_nc_test.py @@ -0,0 +1,59 @@ +#! /usr/bin/python +# +# 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. + +"""Negative compilation unit tests for arena API.""" + +from google3.testing.pybase import fake_target_util +from google.apputils import basetest + + +class ArenaNcTest(basetest.TestCase): + + def testCompilerErrors(self): + """Runs a list of tests to verify compiler error messages.""" + + # Defines a list of test specs, where each element is a tuple + # (test name, list of regexes for matching the compiler errors). + test_specs = [ + ('ARENA_PRIVATE_CONSTRUCTOR', + [r'calling a protected constructor']), + ('SANITY', None)] + + fake_target_util.AssertCcCompilerErrors( + self, # The current test case. + 'google3/google/protobuf/arena_nc', # The fake target file. + 'arena_nc.o', # The sub-target to build. + test_specs # List of test specifications. + ) + +if __name__ == '__main__': + basetest.main() diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc new file mode 100644 index 00000000..7ab6fad8 --- /dev/null +++ b/src/google/protobuf/arena_unittest.cc @@ -0,0 +1,972 @@ +// 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 + +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace google { +using proto2_arena_unittest::ArenaMessage; +using protobuf_unittest::TestAllTypes; +using protobuf_unittest::TestAllExtensions; +using protobuf_unittest::TestOneof2; +using protobuf_unittest::TestEmptyMessage; + +namespace protobuf { +namespace { + +class Notifier { + public: + Notifier() : count_(0) {} + void Notify() { + count_++; + } + int GetCount() { + return count_; + } + + private: + int count_; +}; + +class SimpleDataType { + public: + SimpleDataType() : notifier_(NULL) {} + void SetNotifier(Notifier* notifier) { + notifier_ = notifier; + } + virtual ~SimpleDataType() { + if (notifier_ != NULL) { + notifier_->Notify(); + } + }; + private: + Notifier* notifier_; +}; +} // namespace + +TEST(ArenaTest, ArenaConstructable) { + EXPECT_TRUE(Arena::is_arena_constructable::type::value); + EXPECT_TRUE(Arena::is_arena_constructable::type::value); + EXPECT_FALSE(Arena::is_arena_constructable::type::value); +} + +TEST(ArenaTest, BasicCreate) { + Arena arena; + EXPECT_TRUE(Arena::Create(&arena) != NULL); + EXPECT_TRUE(Arena::Create(&arena) != NULL); + EXPECT_TRUE(Arena::Create(&arena) != NULL); + EXPECT_TRUE(Arena::Create(&arena) != NULL); + EXPECT_TRUE(Arena::Create(&arena) != NULL); + arena.Own(new int32); + arena.Own(new int64); + arena.Own(new float); + arena.Own(new double); + arena.Own(new string); + arena.Own(NULL); + Notifier notifier; + SimpleDataType* data = Arena::Create(&arena); + data->SetNotifier(¬ifier); + data = new SimpleDataType; + data->SetNotifier(¬ifier); + arena.Own(data); + arena.Reset(); + EXPECT_EQ(2, notifier.GetCount()); +} + +TEST(ArenaTest, Parsing) { + TestAllTypes original; + TestUtil::SetAllFields(&original); + + // Test memory leak. + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + TestUtil::ExpectAllFieldsSet(*arena_message); + + // Test that string fields have null terminator bytes (earlier bug). + EXPECT_EQ(strlen(original.optional_string().c_str()), + strlen(arena_message->optional_string().c_str())); +} + +TEST(ArenaTest, UnknownFields) { + TestAllTypes original; + TestUtil::SetAllFields(&original); + + // Test basic parsing into (populating) and reading out of unknown fields on + // an arena. + Arena arena; + TestEmptyMessage* arena_message = + Arena::CreateMessage(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + + TestAllTypes copied; + copied.ParseFromString(arena_message->SerializeAsString()); + TestUtil::ExpectAllFieldsSet(copied); + + // Exercise UFS manual manipulation (setters). + arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_unknown_fields()->AddVarint( + TestAllTypes::kOptionalInt32FieldNumber, 42); + copied.Clear(); + copied.ParseFromString(arena_message->SerializeAsString()); + EXPECT_TRUE(copied.has_optional_int32()); + EXPECT_EQ(42, copied.optional_int32()); + + // Exercise UFS swap path. + TestEmptyMessage* arena_message_2 = + Arena::CreateMessage(&arena); + arena_message_2->Swap(arena_message); + copied.Clear(); + copied.ParseFromString(arena_message_2->SerializeAsString()); + EXPECT_TRUE(copied.has_optional_int32()); + EXPECT_EQ(42, copied.optional_int32()); + + // Test field manipulation. + TestEmptyMessage* arena_message_3 = + Arena::CreateMessage(&arena); + arena_message_3->mutable_unknown_fields()->AddVarint(1000, 42); + arena_message_3->mutable_unknown_fields()->AddFixed32(1001, 42); + arena_message_3->mutable_unknown_fields()->AddFixed64(1002, 42); + arena_message_3->mutable_unknown_fields()->AddLengthDelimited(1003); + arena_message_3->mutable_unknown_fields()->DeleteSubrange(0, 2); + arena_message_3->mutable_unknown_fields()->DeleteByNumber(1002); + arena_message_3->mutable_unknown_fields()->DeleteByNumber(1003); + EXPECT_TRUE(arena_message_3->unknown_fields().empty()); +} + +TEST(ArenaTest, Swap) { + Arena arena1; + Arena arena2; + TestAllTypes* arena1_message; + TestAllTypes* arena2_message; + + // Case 1: Swap(), no UFS on either message, both messages on different + // arenas. Arena pointers should remain the same after swap. + arena1_message = Arena::CreateMessage(&arena1); + arena2_message = Arena::CreateMessage(&arena2); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + + // Case 2: Swap(), UFS on one message, both messages on different arenas. + arena1_message = Arena::CreateMessage(&arena1); + arena2_message = Arena::CreateMessage(&arena2); + arena1_message->mutable_unknown_fields()->AddVarint(1, 42); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + EXPECT_EQ(0, arena1_message->unknown_fields().field_count()); + EXPECT_EQ(1, arena2_message->unknown_fields().field_count()); + EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint()); + + // Case 3: Swap(), UFS on both messages, both messages on different arenas. + arena1_message = Arena::CreateMessage(&arena1); + arena2_message = Arena::CreateMessage(&arena2); + arena1_message->mutable_unknown_fields()->AddVarint(1, 42); + arena2_message->mutable_unknown_fields()->AddVarint(2, 84); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + EXPECT_EQ(1, arena1_message->unknown_fields().field_count()); + EXPECT_EQ(1, arena2_message->unknown_fields().field_count()); + EXPECT_EQ(84, arena1_message->unknown_fields().field(0).varint()); + EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint()); +} + +TEST(ArenaTest, SetAllocatedMessage) { + Arena arena; + TestAllTypes *arena_message = Arena::CreateMessage(&arena); + TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; + nested->set_bb(118); + arena_message->set_allocated_optional_nested_message(nested); + EXPECT_EQ(118, arena_message->optional_nested_message().bb()); + + protobuf_unittest_no_arena::TestNoArenaMessage no_arena_message; + EXPECT_FALSE(no_arena_message.has_arena_message()); + no_arena_message.set_allocated_arena_message(NULL); + EXPECT_FALSE(no_arena_message.has_arena_message()); + no_arena_message.set_allocated_arena_message(new ArenaMessage); + EXPECT_TRUE(no_arena_message.has_arena_message()); +} + +TEST(ArenaTest, ReleaseMessage) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(118); + scoped_ptr nested( + arena_message->release_optional_nested_message()); + EXPECT_EQ(118, nested->bb()); + + TestAllTypes::NestedMessage* released_null = + arena_message->release_optional_nested_message(); + EXPECT_EQ(NULL, released_null); +} + +TEST(ArenaTest, SetAllocatedString) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + string* allocated_str = new string("hello"); + arena_message->set_allocated_optional_string(allocated_str); + EXPECT_EQ("hello", arena_message->optional_string()); +} + +TEST(ArenaTest, ReleaseString) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->set_optional_string("hello"); + scoped_ptr released_str( + arena_message->release_optional_string()); + EXPECT_EQ("hello", *released_str); + + // Test default value. +} + + +TEST(ArenaTest, SwapBetweenArenasWithAllFieldsSet) { + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + { + Arena arena2; + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena2_message); + arena2_message->Swap(arena1_message); + string output; + arena2_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + } + TestUtil::ExpectAllFieldsSet(*arena1_message); +} + +TEST(ArenaTest, SwapBetweenArenaAndNonArenaWithAllFieldsSet) { + TestAllTypes non_arena_message; + TestUtil::SetAllFields(&non_arena_message); + { + Arena arena2; + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena2_message); + arena2_message->Swap(&non_arena_message); + TestUtil::ExpectAllFieldsSet(*arena2_message); + TestUtil::ExpectAllFieldsSet(non_arena_message); + } +} + +TEST(ArenaTest, UnsafeArenaSwap) { + Arena shared_arena; + TestAllTypes* message1 = Arena::CreateMessage(&shared_arena); + TestAllTypes* message2 = Arena::CreateMessage(&shared_arena); + TestUtil::SetAllFields(message1); + message1->UnsafeArenaSwap(message2); + TestUtil::ExpectAllFieldsSet(*message2); +} + +TEST(ArenaTest, SwapBetweenArenasUsingReflection) { + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + { + Arena arena2; + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena2_message); + const Reflection* r = arena2_message->GetReflection(); + r->Swap(arena1_message, arena2_message); + string output; + arena2_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + } + TestUtil::ExpectAllFieldsSet(*arena1_message); +} + +TEST(ArenaTest, SwapBetweenArenaAndNonArenaUsingReflection) { + TestAllTypes non_arena_message; + TestUtil::SetAllFields(&non_arena_message); + { + Arena arena2; + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena2_message); + const Reflection* r = arena2_message->GetReflection(); + r->Swap(&non_arena_message, arena2_message); + TestUtil::ExpectAllFieldsSet(*arena2_message); + TestUtil::ExpectAllFieldsSet(non_arena_message); + } +} + +TEST(ArenaTest, ReleaseFromArenaMessageMakesCopy) { + TestAllTypes::NestedMessage* nested_msg = NULL; + string* nested_string = NULL; + { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(42); + *arena_message->mutable_optional_string() = "Hello"; + nested_msg = arena_message->release_optional_nested_message(); + nested_string = arena_message->release_optional_string(); + } + EXPECT_EQ(42, nested_msg->bb()); + EXPECT_EQ("Hello", *nested_string); + delete nested_msg; + delete nested_string; +} + +TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) { + TestAllTypes::NestedMessage* nested_msg = NULL; + // Note: no string: reflection API only supports releasing submessages. + { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(42); + const Reflection* r = arena_message->GetReflection(); + const FieldDescriptor* f = arena_message->GetDescriptor()->FindFieldByName( + "optional_nested_message"); + nested_msg = dynamic_cast( + r->ReleaseMessage(arena_message, f)); + } + EXPECT_EQ(42, nested_msg->bb()); + delete nested_msg; +} + +TEST(ArenaTest, UnsafeArenaReleaseDoesNotMakeCopy) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + TestAllTypes::NestedMessage* nested_msg = NULL; + TestAllTypes::NestedMessage* orig_nested_msg = NULL; + string* nested_string = NULL; + string* orig_nested_string = NULL; + arena_message->mutable_optional_nested_message()->set_bb(42); + *arena_message->mutable_optional_string() = "Hello"; + orig_nested_msg = arena_message->mutable_optional_nested_message(); + orig_nested_string = arena_message->mutable_optional_string(); + nested_msg = arena_message->unsafe_arena_release_optional_nested_message(); + nested_string = arena_message->unsafe_arena_release_optional_string(); + + EXPECT_EQ(orig_nested_msg, nested_msg); + EXPECT_EQ(orig_nested_string, nested_string); + // Released pointers still on arena; no 'delete' calls needed here. +} + +TEST(ArenaTest, SetAllocatedAcrossArenas) { + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + TestAllTypes::NestedMessage* heap_submessage = + new TestAllTypes::NestedMessage(); + heap_submessage->set_bb(42); + arena1_message->set_allocated_optional_nested_message(heap_submessage); + // Should keep same object and add to arena's Own()-list. + EXPECT_EQ(heap_submessage, + arena1_message->mutable_optional_nested_message()); + { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + arena1_message->set_allocated_optional_nested_message(arena2_submessage); + EXPECT_NE(arena2_submessage, + arena1_message->mutable_optional_nested_message()); + } + + TestAllTypes::NestedMessage* arena1_submessage = + Arena::CreateMessage(&arena1); + arena1_submessage->set_bb(42); + TestAllTypes* heap_message = new TestAllTypes; + heap_message->set_allocated_optional_nested_message(arena1_submessage); + EXPECT_NE(arena1_submessage, + heap_message->mutable_optional_nested_message()); + delete heap_message; +} + +TEST(ArenaTest, SetAllocatedAcrossArenasWithReflection) { + // Same as above, with reflection. + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + const Reflection* r = arena1_message->GetReflection(); + const Descriptor* d = arena1_message->GetDescriptor(); + const FieldDescriptor* msg_field = d->FindFieldByName( + "optional_nested_message"); + TestAllTypes::NestedMessage* heap_submessage = + new TestAllTypes::NestedMessage(); + heap_submessage->set_bb(42); + r->SetAllocatedMessage(arena1_message, heap_submessage, msg_field); + // Should keep same object and add to arena's Own()-list. + EXPECT_EQ(heap_submessage, + arena1_message->mutable_optional_nested_message()); + { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + r->SetAllocatedMessage(arena1_message, arena2_submessage, msg_field); + EXPECT_NE(arena2_submessage, + arena1_message->mutable_optional_nested_message()); + } + + TestAllTypes::NestedMessage* arena1_submessage = + Arena::CreateMessage(&arena1); + arena1_submessage->set_bb(42); + TestAllTypes* heap_message = new TestAllTypes; + r->SetAllocatedMessage(heap_message, arena1_submessage, msg_field); + EXPECT_NE(arena1_submessage, + heap_message->mutable_optional_nested_message()); + delete heap_message; +} + +TEST(ArenaTest, AddAllocatedWithReflection) { + Arena arena1; + ArenaMessage* arena1_message = Arena::CreateMessage(&arena1); + const Reflection* r = arena1_message->GetReflection(); + const Descriptor* d = arena1_message->GetDescriptor(); + const FieldDescriptor* fd = + d->FindFieldByName("repeated_import_no_arena_message"); + // Message with cc_enable_arenas = false; + r->AddMessage(arena1_message, fd); + r->AddMessage(arena1_message, fd); + r->AddMessage(arena1_message, fd); + EXPECT_EQ(3, r->FieldSize(*arena1_message, fd)); + // Message with cc_enable_arenas = true; + fd = d->FindFieldByName("repeated_nested_message"); + r->AddMessage(arena1_message, fd); + r->AddMessage(arena1_message, fd); + r->AddMessage(arena1_message, fd); + EXPECT_EQ(3, r->FieldSize(*arena1_message, fd)); +} + +TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) { + { + RepeatedPtrField repeated_field; + EXPECT_TRUE(repeated_field.empty()); + EXPECT_EQ(0, repeated_field.size()); + // Ownership is passed to repeated_field. + TestAllTypes* cleared = new TestAllTypes(); + repeated_field.AddCleared(cleared); + EXPECT_TRUE(repeated_field.empty()); + EXPECT_EQ(0, repeated_field.size()); + } + { + RepeatedPtrField repeated_field; + EXPECT_TRUE(repeated_field.empty()); + EXPECT_EQ(0, repeated_field.size()); + // Ownership is passed to repeated_field. + TestAllTypes* cleared = new TestAllTypes(); + repeated_field.AddAllocated(cleared); + EXPECT_FALSE(repeated_field.empty()); + EXPECT_EQ(1, repeated_field.size()); + } +} + +// N.B.: no reflection version of this test because all the arena-specific code +// is in RepeatedPtrField, and the reflection works implicitly based on that. +TEST(ArenaTest, AddAllocatedToRepeatedField) { + // Heap->arena case. + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + for (int i = 0; i < 10; i++) { + TestAllTypes::NestedMessage* heap_submessage = + new TestAllTypes::NestedMessage(); + heap_submessage->set_bb(42); + arena1_message->mutable_repeated_nested_message()-> + AddAllocated(heap_submessage); + // Should not copy object -- will use arena_->Own(). + EXPECT_EQ(heap_submessage, + &arena1_message->repeated_nested_message(i)); + EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb()); + } + + // Arena1->Arena2 case. + arena1_message->Clear(); + for (int i = 0; i < 10; i++) { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + arena1_message->mutable_repeated_nested_message()-> + AddAllocated(arena2_submessage); + // Should copy object. + EXPECT_NE(arena2_submessage, + &arena1_message->repeated_nested_message(i)); + EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb()); + } + + // Arena->heap case. + TestAllTypes* heap_message = new TestAllTypes(); + for (int i = 0; i < 10; i++) { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + heap_message->mutable_repeated_nested_message()-> + AddAllocated(arena2_submessage); + // Should copy object. + EXPECT_NE(arena2_submessage, + &heap_message->repeated_nested_message(i)); + EXPECT_EQ(42, heap_message->repeated_nested_message(i).bb()); + } + delete heap_message; + + // Heap-arena case for strings (which are not arena-allocated). + arena1_message->Clear(); + for (int i = 0; i < 10; i++) { + string* s = new string("Test"); + arena1_message->mutable_repeated_string()-> + AddAllocated(s); + // Should not copy. + EXPECT_EQ(s, &arena1_message->repeated_string(i)); + EXPECT_EQ("Test", arena1_message->repeated_string(i)); + } +} + +TEST(ArenaTest, ReleaseLastRepeatedField) { + // Release from arena-allocated repeated field and ensure that returned object + // is heap-allocated. + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + for (int i = 0; i < 10; i++) { + TestAllTypes::NestedMessage* nested = + Arena::CreateMessage(&arena); + nested->set_bb(42); + arena_message->mutable_repeated_nested_message()->AddAllocated(nested); + } + + for (int i = 0; i < 10; i++) { + const TestAllTypes::NestedMessage *orig_submessage = + &arena_message->repeated_nested_message(10 - 1 - i); // last element + TestAllTypes::NestedMessage *released = + arena_message->mutable_repeated_nested_message()->ReleaseLast(); + EXPECT_NE(released, orig_submessage); + EXPECT_EQ(42, released->bb()); + delete released; + } + + // Test UnsafeArenaReleaseLast(). + for (int i = 0; i < 10; i++) { + TestAllTypes::NestedMessage* nested = + Arena::CreateMessage(&arena); + nested->set_bb(42); + arena_message->mutable_repeated_nested_message()->AddAllocated(nested); + } + + for (int i = 0; i < 10; i++) { + const TestAllTypes::NestedMessage *orig_submessage = + &arena_message->repeated_nested_message(10 - 1 - i); // last element + TestAllTypes::NestedMessage *released = + arena_message->mutable_repeated_nested_message()-> + UnsafeArenaReleaseLast(); + EXPECT_EQ(released, orig_submessage); + EXPECT_EQ(42, released->bb()); + // no delete -- |released| is on the arena. + } + + // Test string case as well. ReleaseLast() in this case must copy the string, + // even though it was originally heap-allocated and its pointer was simply + // appended to the repeated field's internal vector, because the string was + // placed on the arena's destructor list and cannot be removed from that list + // (so the arena permanently owns the original instance). + arena_message->Clear(); + for (int i = 0; i < 10; i++) { + string* s = new string("Test"); + arena_message->mutable_repeated_string()->AddAllocated(s); + } + for (int i = 0; i < 10; i++) { + const string* orig_element = &arena_message->repeated_string(10 - 1 - i); + string* released = arena_message->mutable_repeated_string()->ReleaseLast(); + EXPECT_NE(released, orig_element); + EXPECT_EQ("Test", *released); + delete released; + } +} + +TEST(ArenaTest, UnsafeArenaReleaseAdd) { + // Use unsafe_arena_release() and unsafe_arena_set_allocated() to transfer an + // arena-allocated string from one message to another. + Arena arena; + TestAllTypes* message1 = Arena::CreateMessage(&arena); + TestAllTypes* message2 = Arena::CreateMessage(&arena); + string* arena_string = Arena::Create(&arena); + *arena_string = "Test content"; + + message1->unsafe_arena_set_allocated_optional_string(arena_string); + EXPECT_EQ(arena_string, message1->mutable_optional_string()); + message2->unsafe_arena_set_allocated_optional_string( + message1->unsafe_arena_release_optional_string()); + EXPECT_EQ(arena_string, message2->mutable_optional_string()); +} + +TEST(ArenaTest, UnsafeArenaAddAllocated) { + Arena arena; + TestAllTypes* message = Arena::CreateMessage(&arena); + for (int i = 0; i < 10; i++) { + string* arena_string = Arena::Create(&arena); + message->mutable_repeated_string()->UnsafeArenaAddAllocated(arena_string); + EXPECT_EQ(arena_string, message->mutable_repeated_string(i)); + } +} + +namespace { +void TestSwapRepeatedField(Arena* arena1, Arena* arena2) { + // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField + // between arenas. + RepeatedPtrField field1(arena1); + RepeatedPtrField field2(arena2); + for (int i = 0; i < 10; i++) { + TestAllTypes* t = Arena::CreateMessage(arena1); + t->set_optional_string("field1"); + t->set_optional_int32(i); + if (arena1 != NULL) { + field1.UnsafeArenaAddAllocated(t); + } else { + field1.AddAllocated(t); + } + } + for (int i = 0; i < 5; i++) { + TestAllTypes* t = Arena::CreateMessage(arena2); + t->set_optional_string("field2"); + t->set_optional_int32(i); + if (arena2 != NULL) { + field2.UnsafeArenaAddAllocated(t); + } else { + field2.AddAllocated(t); + } + } + field1.Swap(&field2); + EXPECT_EQ(5, field1.size()); + EXPECT_EQ(10, field2.size()); + EXPECT_TRUE(string("field1") == field2.Get(0).optional_string()); + EXPECT_TRUE(string("field2") == field1.Get(0).optional_string()); + // Ensure that fields retained their original order: + for (int i = 0; i < field1.size(); i++) { + EXPECT_EQ(i, field1.Get(i).optional_int32()); + } + for (int i = 0; i < field2.size(); i++) { + EXPECT_EQ(i, field2.Get(i).optional_int32()); + } +} +} // namespace + +TEST(ArenaTest, SwapRepeatedField) { + Arena arena; + TestSwapRepeatedField(&arena, &arena); +} + +TEST(ArenaTest, SwapRepeatedFieldWithDifferentArenas) { + Arena arena1; + Arena arena2; + TestSwapRepeatedField(&arena1, &arena2); +} + +TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnRightHandSide) { + Arena arena; + TestSwapRepeatedField(&arena, NULL); +} + +TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnLeftHandSide) { + Arena arena; + TestSwapRepeatedField(NULL, &arena); +} + +TEST(ArenaTest, ExtensionsOnArena) { + Arena arena; + // Ensure no leaks. + TestAllExtensions* message_ext = + Arena::CreateMessage(&arena); + message_ext->SetExtension( + protobuf_unittest::optional_int32_extension, 42); + message_ext->SetExtension( + protobuf_unittest::optional_string_extension, string("test")); + message_ext->MutableExtension( + protobuf_unittest::optional_nested_message_extension)->set_bb(42); +} + +class NoHeapChecker { + public: + NoHeapChecker() { + capture_alloc.Hook(); + } + ~NoHeapChecker() { + capture_alloc.Unhook(); + EXPECT_EQ(0, capture_alloc.alloc_count()); + EXPECT_EQ(0, capture_alloc.free_count()); + } + private: + class NewDeleteCapture { + public: + // TOOD(xiaofeng): Implement this for opensource protobuf. + void Hook() {} + void Unhook() {} + int alloc_count() { return 0; } + int free_count() { return 0; } + } capture_alloc; +}; + +TEST(ArenaTest, RepeatedFieldOnArena) { + // Preallocate an initial arena block to avoid mallocs during hooked region. + std::vector arena_block(1024 * 1024); + ArenaOptions options; + options.initial_block = arena_block.data(); + options.initial_block_size = arena_block.size(); + Arena arena(options); + + { + NoHeapChecker no_heap; + + // Fill some repeated fields on the arena to test for leaks. Also verify no + // memory allocations. + RepeatedField repeated_int32(&arena); + RepeatedPtrField repeated_message(&arena); + for (int i = 0; i < 100; i++) { + repeated_int32.Add(42); + repeated_message.Add()->set_optional_int32(42); + EXPECT_EQ(&arena, repeated_message.Get(0).GetArena()); + const TestAllTypes* msg_in_repeated_field = &repeated_message.Get(0); + TestAllTypes* msg = repeated_message.UnsafeArenaReleaseLast(); + EXPECT_EQ(msg_in_repeated_field, msg); + } + + // UnsafeArenaExtractSubrange (i) should not leak and (ii) should return + // on-arena pointers. + for (int i = 0; i < 10; i++) { + repeated_message.Add()->set_optional_int32(42); + } + TestAllTypes* extracted_messages[5]; + repeated_message.UnsafeArenaExtractSubrange(0, 5, extracted_messages); + EXPECT_EQ(&arena, repeated_message.Get(0).GetArena()); + EXPECT_EQ(5, repeated_message.size()); + } + + // Now, outside the scope of the NoHeapChecker, test ExtractSubrange's copying + // semantics. + { + RepeatedPtrField repeated_message(&arena); + for (int i = 0; i < 100; i++) { + repeated_message.Add()->set_optional_int32(42); + } + + TestAllTypes* extracted_messages[5]; + // ExtractSubrange should copy to the heap. + repeated_message.ExtractSubrange(0, 5, extracted_messages); + EXPECT_EQ(NULL, extracted_messages[0]->GetArena()); + // We need to free the heap-allocated messages to prevent a leak. + for (int i = 0; i < 5; i++) { + delete extracted_messages[i]; + extracted_messages[i] = NULL; + } + } + + // Now check that we can create RepeatedFields/RepeatedPtrFields themselves on + // the arena. They have the necessary type traits so that they can behave like + // messages in this way. This is useful for higher-level generic templated + // code that may allocate messages or repeated fields of messages on an arena. + { + RepeatedPtrField* repeated_ptr_on_arena = + Arena::CreateMessage< RepeatedPtrField >(&arena); + for (int i = 0; i < 10; i++) { + // Add some elements and let the leak-checker ensure that everything is + // freed. + repeated_ptr_on_arena->Add(); + } + + RepeatedField* repeated_int_on_arena = + Arena::CreateMessage< RepeatedField >(&arena); + for (int i = 0; i < 100; i++) { + repeated_int_on_arena->Add(i); + } + + } + + arena.Reset(); +} + + +TEST(ArenaTest, MutableMessageReflection) { + Arena arena; + TestAllTypes* message = Arena::CreateMessage(&arena); + const Reflection* r = message->GetReflection(); + const Descriptor* d = message->GetDescriptor(); + const FieldDescriptor* field = d->FindFieldByName("optional_nested_message"); + TestAllTypes::NestedMessage* submessage = + dynamic_cast( + r->MutableMessage(message, field)); + TestAllTypes::NestedMessage* submessage_expected = + message->mutable_optional_nested_message(); + + EXPECT_EQ(submessage_expected, submessage); + EXPECT_EQ(&arena, submessage->GetArena()); + + const FieldDescriptor* oneof_field = d->FindFieldByName("oneof_nested_message"); + submessage = dynamic_cast( + r->MutableMessage(message, oneof_field)); + submessage_expected = message->mutable_oneof_nested_message(); + + EXPECT_EQ(submessage_expected, submessage); + EXPECT_EQ(&arena, submessage->GetArena()); +} + + +namespace { + +void FillArenaAwareFields(TestAllTypes* message) { + string test_string = "hello world"; + message->set_optional_int32(42); + message->set_optional_string(test_string); + message->set_optional_bytes(test_string); + message->mutable_optional_nested_message()->set_bb(42); + + message->set_oneof_uint32(42); + message->mutable_oneof_nested_message()->set_bb(42); + message->set_oneof_string(test_string); + message->set_oneof_bytes(test_string); + + message->add_repeated_int32(42); + // No repeated string: not yet arena-aware. + message->add_repeated_nested_message()->set_bb(42); + message->mutable_optional_lazy_message()->set_bb(42); +} + +} + +// Test: no allocations occur on heap while touching all supported field types. +TEST(ArenaTest, NoHeapAllocationsTest) { + // Allocate a large initial block to avoid mallocs during hooked test. + std::vector arena_block(128 * 1024); + ArenaOptions options; + options.initial_block = arena_block.data(); + options.initial_block_size = arena_block.size(); + Arena arena(options); + + { + + TestAllTypes* message = Arena::CreateMessage(&arena); + FillArenaAwareFields(message); + } + + arena.Reset(); +} + + +// Test construction on an arena via generic MessageLite interface. We should be +// able to successfully deserialize on the arena without incurring heap +// allocations, i.e., everything should still be arena-allocation-aware. +TEST(ArenaTest, MessageLiteOnArena) { + std::vector arena_block(128 * 1024); + ArenaOptions options; + options.initial_block = arena_block.data(); + options.initial_block_size = arena_block.size(); + Arena arena(options); + const google::protobuf::MessageLite* prototype = dynamic_cast< + const google::protobuf::MessageLite*>(&TestAllTypes::default_instance()); + + TestAllTypes initial_message; + FillArenaAwareFields(&initial_message); + string serialized; + initial_message.SerializeToString(&serialized); + + { + + google::protobuf::MessageLite* generic_message = prototype->New(&arena); + EXPECT_TRUE(generic_message != NULL); + EXPECT_EQ(&arena, generic_message->GetArena()); + EXPECT_TRUE(generic_message->ParseFromString(serialized)); + TestAllTypes* deserialized = dynamic_cast(generic_message); + EXPECT_TRUE(deserialized != NULL); + EXPECT_EQ(42, deserialized->optional_int32()); + } + + arena.Reset(); +} + + +// RepeatedField should support non-POD types, and invoke constructors and +// destructors appropriately, because it's used this way by lots of other code +// (even if this was not its original intent). +TEST(ArenaTest, RepeatedFieldWithNonPODType) { + { + RepeatedField field_on_heap; + for (int i = 0; i < 100; i++) { + *field_on_heap.Add() = "test string long enough to exceed inline buffer"; + } + } + { + Arena arena; + RepeatedField field_on_arena(&arena); + for (int i = 0; i < 100; i++) { + *field_on_arena.Add() = "test string long enough to exceed inline buffer"; + } + } +} + +TEST(ArenaTest, SpaceUsed) { + ArenaOptions options; + options.start_block_size = 256; + options.max_block_size = 8192; + Arena arena_1(options); + EXPECT_EQ(0, arena_1.SpaceUsed()); + EXPECT_EQ(0, arena_1.Reset()); + ::google::protobuf::Arena::CreateArray(&arena_1, 320); + // Arena will allocate slightly more than 320 for the block headers. + EXPECT_LE(320, arena_1.SpaceUsed()); + EXPECT_LE(320, arena_1.Reset()); + + // Test with initial block. + std::vector arena_block(1024); + options.initial_block = arena_block.data(); + options.initial_block_size = arena_block.size(); + Arena arena_2(options); + EXPECT_EQ(1024, arena_2.SpaceUsed()); + EXPECT_EQ(1024, arena_2.Reset()); + ::google::protobuf::Arena::CreateArray(&arena_2, 55); + EXPECT_EQ(1024, arena_2.SpaceUsed()); + EXPECT_EQ(1024, arena_2.Reset()); + + // Reset options to test doubling policy explicitly. + options.initial_block = NULL; + options.initial_block_size = 0; + Arena arena_3(options); + ::google::protobuf::Arena::CreateArray(&arena_3, 190); + EXPECT_EQ(256, arena_3.SpaceUsed()); + ::google::protobuf::Arena::CreateArray(&arena_3, 70); + EXPECT_EQ(256 + 512, arena_3.SpaceUsed()); + EXPECT_EQ(256 + 512, arena_3.Reset()); +} + +TEST(ArenaTest, Alignment) { + ::google::protobuf::Arena arena; + for (int i = 0; i < 200; i++) { + void* p = ::google::protobuf::Arena::CreateArray(&arena, i); + GOOGLE_CHECK_EQ(reinterpret_cast(p) % 8, 0) << i << ": " << p; + } +} + +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc new file mode 100644 index 00000000..7f33a0c8 --- /dev/null +++ b/src/google/protobuf/arenastring.cc @@ -0,0 +1,43 @@ +// 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. + +// The ArenaString implementation is not included in the open-source release. Do +// not include this file in the distribution. + +#include + +namespace google { +namespace protobuf { +namespace internal { + + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h new file mode 100755 index 00000000..5f02ef0d --- /dev/null +++ b/src/google/protobuf/arenastring.h @@ -0,0 +1,314 @@ +// 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_ARENASTRING_H__ +#define GOOGLE_PROTOBUF_ARENASTRING_H__ + +#include +#include + +#include +#include + +#include +#include + + + +// This is the implementation of arena string fields written for the open-source +// release. The ArenaStringPtr struct below is an internal implementation class +// and *should not be used* by user code. It is used to collect string +// operations together into one place and abstract away the underlying +// string-field pointer representation, so that (for example) an alternate +// implementation that knew more about ::std::string's internals could integrate more +// closely with the arena allocator. + +namespace google { +namespace protobuf { +namespace internal { + +struct ArenaStringPtr { + inline void Set(const ::std::string* default_value, + const ::std::string& value, ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + CreateInstance(arena, &value); + } else { + *ptr_ = value; + } + } + + // Basic accessors. + inline const ::std::string& Get(const ::std::string* default_value) const { + return *ptr_; + } + + inline ::std::string* Mutable(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + CreateInstance(arena, default_value); + } + return ptr_; + } + + // Release returns a ::std::string* instance that is heap-allocated and is not + // Own()'d by any arena. If the field was not set, it returns NULL. The caller + // retains ownership. Clears this field back to NULL state. Used to implement + // release_() methods on generated classes. + inline ::std::string* Release(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + return NULL; + } + ::std::string* released = NULL; + if (arena != NULL) { + // ptr_ is owned by the arena -- we need to return a copy. + released = new ::std::string(*ptr_); + } else { + released = ptr_; + } + ptr_ = const_cast< ::std::string* >(default_value); + return released; + } + + // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e. + // have its destructor already registered) if arena != NULL. If the field was + // not set, this returns NULL. This method clears this field back to NULL + // state. Used to implement unsafe_arena_release_() methods on + // generated classes. + inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + return NULL; + } + ::std::string* released = ptr_; + ptr_ = const_cast< ::std::string* >(default_value); + return released; + } + + // Takes a string that is heap-allocated, and takes ownership. The string's + // destructor is registered with the arena. Used to implement + // set_allocated_ in generated classes. + inline void SetAllocated(const ::std::string* default_value, + ::std::string* value, ::google::protobuf::Arena* arena) { + if (arena == NULL && ptr_ != default_value) { + Destroy(default_value, arena); + } + if (value != NULL) { + ptr_ = value; + if (arena != NULL) { + arena->Own(value); + } + } else { + ptr_ = const_cast< ::std::string* >(default_value); + } + } + + // Takes a string that has lifetime equal to the arena's lifetime. The arena + // must be non-null. It is safe only to pass this method a value returned by + // UnsafeArenaRelease() on another field of a message in the same arena. Used + // to implement unsafe_arena_set_allocated_ in generated classes. + inline void UnsafeArenaSetAllocated(const ::std::string* default_value, + ::std::string* value, ::google::protobuf::Arena* arena) { + if (value != NULL) { + ptr_ = value; + } else { + ptr_ = const_cast< ::std::string* >(default_value); + } + } + + // Swaps internal pointers. Arena-safety semantics: this is guarded by the + // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is + // 'unsafe' if called directly. + inline void Swap(ArenaStringPtr* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + std::swap(ptr_, other->ptr_); + } + + // Frees storage (if not on an arena) and sets field to default value. + inline void Destroy(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (arena == NULL && ptr_ != default_value) { + delete ptr_; + } + ptr_ = const_cast< ::std::string* >(default_value); + } + + // Clears content, but keeps allocated string if arena != NULL, to avoid the + // overhead of heap operations. After this returns, the content (as seen by + // the user) will always be the empty string. Assumes that |default_value| + // is an empty string. + inline void ClearToEmpty(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + // Already set to default (which is empty) -- do nothing. + } else { + ptr_->clear(); + } + } + + // Clears content, but keeps allocated string if arena != NULL, to avoid the + // overhead of heap operations. After this returns, the content (as seen by + // the user) will always be equal to |default_value|. + inline void ClearToDefault(const ::std::string* default_value, + ::google::protobuf::Arena* arena) { + if (ptr_ == default_value) { + // Already set to default -- do nothing. + } else { + // Have another allocated string -- rather than throwing this away and + // resetting ptr_ to the canonical default string instance, we just reuse + // this instance. + *ptr_ = *default_value; + } + } + + // Called from generated code / reflection runtime only. Resets value to point + // to a default string pointer, with the semantics that this ArenaStringPtr + // does not own the pointed-to memory. Disregards initial value of ptr_ (so + // this is the *ONLY* safe method to call after construction or when + // reinitializing after becoming the active field in a oneof union). + inline void UnsafeSetDefault(const ::std::string* default_value) { + // Casting away 'const' is safe here: accessors ensure that ptr_ is only + // returned as a const if it is equal to default_value. + ptr_ = const_cast< ::std::string* >(default_value); + } + + // The 'NoArena' variants of methods below assume arena == NULL and are + // optimized to provide very little overhead relative to a raw string pointer + // (while still being in-memory compatible with other code that assumes + // ArenaStringPtr). Note the invariant that a class instance that has only + // ever been mutated by NoArena methods must *only* be in the String state + // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all + // tagged-pointer manipulations to be avoided. + inline void SetNoArena(const ::std::string* default_value, + const ::std::string& value) { + if (ptr_ == default_value) { + CreateInstanceNoArena(&value); + } else { + *ptr_ = value; + } + } + + inline const ::std::string& GetNoArena(const ::std::string* default_value) const { + return *ptr_; + } + + inline ::std::string* MutableNoArena(const ::std::string* default_value) { + if (ptr_ == default_value) { + CreateInstanceNoArena(default_value); + } + return ptr_; + } + + inline ::std::string* ReleaseNoArena(const ::std::string* default_value) { + if (ptr_ == default_value) { + return NULL; + } else { + ::std::string* released = ptr_; + ptr_ = const_cast< ::std::string* >(default_value); + return released; + } + } + + inline void SetAllocatedNoArena(const ::std::string* default_value, + ::std::string* value) { + if (ptr_ != default_value) { + delete ptr_; + } + if (value != NULL) { + ptr_ = value; + } else { + ptr_ = const_cast< ::std::string* >(default_value); + } + } + + inline void DestroyNoArena(const ::std::string* default_value) { + if (ptr_ != default_value) { + delete ptr_; + } + ptr_ = NULL; + } + + inline void ClearToEmptyNoArena(const ::std::string* default_value) { + if (ptr_ == default_value) { + // Nothing: already equal to default (which is the empty string). + } else { + ptr_->clear(); + } + } + + inline void ClearToDefaultNoArena(const ::std::string* default_value) { + if (ptr_ == default_value) { + // Nothing: already set to default. + } else { + // Reuse existing allocated instance. + *ptr_ = *default_value; + } + } + + // Internal accessor used only at parse time to provide direct access to the + // raw pointer from the shared parse routine (in the non-arenas case). The + // parse routine does the string allocation in order to save code size in the + // generated parsing code. + inline ::std::string** UnsafeRawStringPointer() { + return &ptr_; + } + + private: + ::std::string* ptr_; + + inline void CreateInstance(::google::protobuf::Arena* arena, + const ::std::string* initial_value) + GOOGLE_ATTRIBUTE_NOINLINE { + // Assumes ptr_ is not NULL. + if (initial_value != NULL) { + ptr_ = new ::std::string(*initial_value); + } else { + ptr_ = new ::std::string(); + } + if (arena != NULL) { + arena->Own(ptr_); + } + } + inline void CreateInstanceNoArena(const ::std::string* initial_value) + GOOGLE_ATTRIBUTE_NOINLINE { + if (initial_value != NULL) { + ptr_ = new ::std::string(*initial_value); + } else { + ptr_ = new ::std::string(); + } + } +}; + +} // namespace internal +} // namespace protobuf + + + +} // namespace google +#endif // GOOGLE_PROTOBUF_ARENASTRING_H__ diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc new file mode 100644 index 00000000..8ebd4b9c --- /dev/null +++ b/src/google/protobuf/arenastring_unittest.cc @@ -0,0 +1,112 @@ +// 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. + +// arenastring_unittest.cc is not open-sourced. Do not include in open-source +// distribution. + +// Based on mvels@'s frankenstring. + +#include + +#include +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include + +namespace google { +using google::protobuf::internal::ArenaString; +using google::protobuf::internal::ArenaStringPtr; + +namespace protobuf { + + +static string WrapString(const char* value) { + return value; +} + +// Test ArenaStringPtr with arena == NULL. +TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) { + ArenaStringPtr field; + ::std::string default_value = "default"; + field.UnsafeSetDefault(&default_value); + EXPECT_EQ(string("default"), field.Get(&default_value)); + field.Set(&default_value, WrapString("Test short"), NULL); + EXPECT_EQ(string("Test short"), field.Get(&default_value)); + field.Set(&default_value, WrapString("Test long long long long value"), NULL); + EXPECT_EQ(string("Test long long long long value"), field.Get(&default_value)); + field.Set(&default_value, string(""), NULL); + field.Destroy(&default_value, NULL); + + ArenaStringPtr field2; + field2.UnsafeSetDefault(&default_value); + ::std::string* mut = field2.Mutable(&default_value, NULL); + EXPECT_EQ(mut, field2.Mutable(&default_value, NULL)); + EXPECT_EQ(mut, &field2.Get(&default_value)); + EXPECT_NE(&default_value, mut); + EXPECT_EQ(string("default"), *mut); + *mut = "Test long long long long value"; // ensure string allocates storage + EXPECT_EQ(string("Test long long long long value"), field2.Get(&default_value)); + field2.Destroy(&default_value, NULL); +} + +TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) { + google::protobuf::Arena arena; + ArenaStringPtr field; + ::std::string default_value = "default"; + field.UnsafeSetDefault(&default_value); + EXPECT_EQ(string("default"), field.Get(&default_value)); + field.Set(&default_value, WrapString("Test short"), &arena); + EXPECT_EQ(string("Test short"), field.Get(&default_value)); + field.Set(&default_value, WrapString("Test long long long long value"), &arena); + EXPECT_EQ(string("Test long long long long value"), + field.Get(&default_value)); + field.Set(&default_value, string(""), &arena); + field.Destroy(&default_value, &arena); + + ArenaStringPtr field2; + field2.UnsafeSetDefault(&default_value); + ::std::string* mut = field2.Mutable(&default_value, &arena); + EXPECT_EQ(mut, field2.Mutable(&default_value, &arena)); + EXPECT_EQ(mut, &field2.Get(&default_value)); + EXPECT_NE(&default_value, mut); + EXPECT_EQ(string("default"), *mut); + *mut = "Test long long long long value"; // ensure string allocates storage + EXPECT_EQ(string("Test long long long long value"), + field2.Get(&default_value)); + field2.Destroy(&default_value, &arena); +} + +} // namespace protobuf +} // namespace google 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 #endif #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -48,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +63,7 @@ #include #include + 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -102,6 +105,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "#define PROTOBUF_$filename_identifier$__INCLUDED\n" "\n" "#include \n" + "#include \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 \n"); + "#include \n" + "#include \n" + "#include \n" + "#include \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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 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 #include #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -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()) { @@ -1380,20 +1609,108 @@ GenerateSharedDestructorCode(io::Printer* printer) { "\n"); } +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 RequiredFieldsBitMask(const Descriptor* desc) { + vector 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& masks) { + vector 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 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 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(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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -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 > nested_generators_; scoped_array > enum_generators_; scoped_array > 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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -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(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(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(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(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(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(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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include +#include #include #include @@ -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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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\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 $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\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 $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($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 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\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 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();\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();\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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include #include #include +#include #include #include #include @@ -48,6 +52,7 @@ #include #include + 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -99,10 +102,14 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector all_files; + vector 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 + +#include +#include +#include +#include +#include + +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* 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 + +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 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 #include #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -264,60 +267,36 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { descriptor_->containing_type() == NULL && MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); + map 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 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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include @@ -68,6 +71,7 @@ class SharedCodeGenerator { void Generate(GeneratorContext* generator_context, vector* 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 #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include 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 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* 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* 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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include #include @@ -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 primitive_type_map = 1;\n" + " map 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 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 int_map = 1;\n" + " required map int_map2 = 2;\n" + " repeated map 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 str_map = 2;\n" + " map str_map2 = 3;\n" + " map<,string> str_map3 = 4;\n" + " map<> empty_map = 5;\n" + " map 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 enum_message_map = 1; " + " map 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(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(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(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 +#include #include @@ -19,7 +20,10 @@ #error regenerate this file with a newer version of protoc. #endif +#include +#include #include +#include #include #include #include @@ -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(value), size); + parameter_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(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(value), size); + insertion_point_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(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(value), size); + content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(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(value), size); + error_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(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 #include #include -#include #include +#ifndef _SHARED_PTR_H +#include +#endif #include +#include #include #include @@ -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 MakeKeywordsMap() { + hash_set result; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); ++i) { + result.insert(kKeywordList[i]); + } + return result; +} + +hash_set* keywords_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(keywords_once_); + +void InitKeywords() { + keywords_ = new hash_set(); + *keywords_ = MakeKeywordsMap(); +} + +hash_set& 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 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 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 +#ifndef _SHARED_PTR_H +#include +#endif #include #include diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 21dda598..ab8691fd 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,17 @@ const char * const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = { "repeated", // LABEL_REPEATED }; +const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) { + switch (syntax) { + case SYNTAX_PROTO2: + return "proto2"; + case SYNTAX_PROTO3: + return "proto3"; + case SYNTAX_UNKNOWN: + return "unknown"; + } +} + static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty"; #ifndef _MSC_VER // MSVC doesn't need these and won't even accept them. @@ -144,8 +156,8 @@ const int FieldDescriptor::kLastReservedNumber; namespace { -string ToCamelCase(const string& input) { - bool capitalize_next = false; +string ToCamelCase(const string& input, bool lower_first) { + bool capitalize_next = !lower_first; string result; result.reserve(input.size()); @@ -166,8 +178,8 @@ string ToCamelCase(const string& input) { } // Lower-case the first letter. - if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') { - result[0] = result[0] - 'A' + 'a'; + if (lower_first && !result.empty() && 'A' <= result[0] && result[0] <= 'Z') { + result[0] = result[0] - 'A' + 'a'; } return result; @@ -327,6 +339,31 @@ typedef hash_map ExtensionsGroupedByDescriptorMap; typedef hash_map LocationsByPathMap; + +set* allowed_proto3_extendees_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_); + +void InitAllowedProto3Extendee() { + allowed_proto3_extendees_ = new set; + allowed_proto3_extendees_->insert("google.protobuf.FileOptions"); + allowed_proto3_extendees_->insert("google.protobuf.MessageOptions"); + allowed_proto3_extendees_->insert("google.protobuf.FieldOptions"); + allowed_proto3_extendees_->insert("google.protobuf.EnumOptions"); + allowed_proto3_extendees_->insert("google.protobuf.EnumValueOptions"); + allowed_proto3_extendees_->insert("google.protobuf.ServiceOptions"); + allowed_proto3_extendees_->insert("google.protobuf.MethodOptions"); +} + +// Checks whether the extendee type is allowed in proto3. +// Only extensions to descriptor options are allowed. We use name comparison +// instead of comparing the descriptor directly because the extensions may be +// defined in a different pool. +bool AllowedExtendeeInProto3(const string& name) { + ::google::protobuf::GoogleOnceInit(&allowed_proto3_extendees_init_, &InitAllowedProto3Extendee); + return allowed_proto3_extendees_->find(name) != + allowed_proto3_extendees_->end(); +} + } // anonymous namespace // =================================================================== @@ -532,6 +569,9 @@ class FileDescriptorTables { const void* parent, const string& camelcase_name) const; inline const EnumValueDescriptor* FindEnumValueByNumber( const EnumDescriptor* parent, int number) const; + // This creates a new EnumValueDescriptor if not found, in a thread-safe way. + inline const EnumValueDescriptor* FindEnumValueByNumberCreatingIfUnknown( + const EnumDescriptor* parent, int number) const; // ----------------------------------------------------------------- // Adding items. @@ -567,10 +607,16 @@ class FileDescriptorTables { FieldsByNameMap fields_by_camelcase_name_; FieldsByNumberMap fields_by_number_; // Not including extensions. EnumValuesByNumberMap enum_values_by_number_; + mutable EnumValuesByNumberMap unknown_enum_values_by_number_ + GOOGLE_GUARDED_BY(unknown_enum_values_mu_); // Populated on first request to save space, hence constness games. mutable GoogleOnceDynamic locations_by_path_once_; mutable LocationsByPathMap locations_by_path_; + + // Mutex to protect the unknown-enum-value map due to dynamic + // EnumValueDescriptor creation on unknown values. + mutable Mutex unknown_enum_values_mu_; }; DescriptorPool::Tables::Tables() @@ -600,7 +646,8 @@ FileDescriptorTables::FileDescriptorTables() fields_by_lowercase_name_(3), fields_by_camelcase_name_(3), fields_by_number_(3), - enum_values_by_number_(3) { + enum_values_by_number_(3), + unknown_enum_values_by_number_(3) { } FileDescriptorTables::~FileDescriptorTables() {} @@ -749,6 +796,60 @@ inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber( return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number)); } +inline const EnumValueDescriptor* +FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown( + const EnumDescriptor* parent, int number) const { + // First try, with map of compiled-in values. + { + const EnumValueDescriptor* desc = FindPtrOrNull( + enum_values_by_number_, make_pair(parent, number)); + if (desc != NULL) { + return desc; + } + } + // Second try, with reader lock held on unknown enum values: common case. + { + ReaderMutexLock l(&unknown_enum_values_mu_); + const EnumValueDescriptor* desc = FindPtrOrNull( + unknown_enum_values_by_number_, make_pair(parent, number)); + if (desc != NULL) { + return desc; + } + } + // If not found, try again with writer lock held, and create new descriptor if + // necessary. + { + WriterMutexLock l(&unknown_enum_values_mu_); + const EnumValueDescriptor* desc = FindPtrOrNull( + unknown_enum_values_by_number_, make_pair(parent, number)); + if (desc != NULL) { + return desc; + } + + // Create an EnumValueDescriptor dynamically. We don't insert it into the + // EnumDescriptor (it's not a part of the enum as originally defined), but + // we do insert it into the table so that we can return the same pointer + // later. + string enum_value_name = StringPrintf( + "UNKNOWN_ENUM_VALUE_%s_%d", parent->name().c_str(), number); + DescriptorPool::Tables* tables = + const_cast(DescriptorPool::generated_pool()-> + tables_.get()); + EnumValueDescriptor* result = tables->Allocate(); + result->name_ = tables->AllocateString(enum_value_name); + result->full_name_ = tables->AllocateString(parent->full_name() + + "." + enum_value_name); + result->number_ = number; + result->type_ = parent; + result->options_ = &EnumValueOptions::default_instance(); + InsertIfNotPresent(&unknown_enum_values_by_number_, + make_pair(parent, number), + result); + return result; + } +} + + inline const FieldDescriptor* DescriptorPool::Tables::FindExtension( const Descriptor* extendee, int number) { return FindPtrOrNull(extensions_, make_pair(extendee, number)); @@ -1311,6 +1412,11 @@ EnumDescriptor::FindValueByNumber(int key) const { return file()->tables_->FindEnumValueByNumber(this, key); } +const EnumValueDescriptor* +EnumDescriptor::FindValueByNumberCreatingIfUnknown(int key) const { + return file()->tables_->FindEnumValueByNumberCreatingIfUnknown(this, key); +} + const MethodDescriptor* ServiceDescriptor::FindMethodByName(const string& key) const { Symbol result = @@ -1562,6 +1668,8 @@ string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const { void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { proto->set_name(name()); if (!package().empty()) proto->set_package(package()); + // TODO(liujisi): Also populate when syntax="proto2". + if (syntax() == SYNTAX_PROTO3) proto->set_syntax(SyntaxName(syntax())); for (int i = 0; i < dependency_count(); i++) { proto->add_dependency(dependency(i)->name()); @@ -1594,7 +1702,8 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { } void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const { - if (source_code_info_ != &SourceCodeInfo::default_instance()) { + if (source_code_info_ && + source_code_info_ != &SourceCodeInfo::default_instance()) { proto->mutable_source_code_info()->CopyFrom(*source_code_info_); } } @@ -1802,10 +1911,67 @@ bool FormatLineOptions(int depth, const Message &options, string *output) { return !all_options.empty(); } +template +class SourceLocationCommentPrinter { + public: + SourceLocationCommentPrinter(const DescType* desc, + const string& prefix, + const DebugStringOptions& options) + : options_(options), prefix_(prefix) { + // Perform the SourceLocation lookup only if we're including user comments, + // because the lookup is fairly expensive. + have_source_loc_ = options.include_comments && + desc->GetSourceLocation(&source_loc_); + } + void AddPreComment(string* output) { + if (have_source_loc_ && source_loc_.leading_comments.size() > 0) { + *output += FormatComment(source_loc_.leading_comments); + } + } + void AddPostComment(string* output) { + if (have_source_loc_ && source_loc_.trailing_comments.size() > 0) { + *output += FormatComment(source_loc_.trailing_comments); + } + } + + // Format comment such that each line becomes a full-line C++-style comment in + // the DebugString() output. + string FormatComment(const string& comment_text) { + string stripped_comment = comment_text; + StripWhitespace(&stripped_comment); + vector lines = Split(stripped_comment, "\n"); + string output; + for (int i = 0; i < lines.size(); ++i) { + const string& line = lines[i]; + strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line); + } + return output; + } + + private: + const DescType* desc_; + bool have_source_loc_; + SourceLocation source_loc_; + DebugStringOptions options_; + string prefix_; +}; + } // anonymous namespace string FileDescriptor::DebugString() const { - string contents = "syntax = \"proto2\";\n\n"; + DebugStringOptions options; // default options + return DebugStringWithOptions(options); +} + +string FileDescriptor::DebugStringWithOptions( + const DebugStringOptions& debug_string_options) const { + string contents; + strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n", + SyntaxName(syntax())); + + SourceLocationCommentPrinter + comment_printer(this, "", debug_string_options); + comment_printer.AddPreComment(&contents); set public_dependencies; set weak_dependencies; @@ -1836,7 +2002,7 @@ string FileDescriptor::DebugString() const { } for (int i = 0; i < enum_type_count(); i++) { - enum_type(i)->DebugString(0, &contents); + enum_type(i)->DebugString(0, &contents, debug_string_options); contents.append("\n"); } @@ -1851,15 +2017,14 @@ string FileDescriptor::DebugString() const { for (int i = 0; i < message_type_count(); i++) { if (groups.count(message_type(i)) == 0) { - strings::SubstituteAndAppend(&contents, "message $0", - message_type(i)->name()); - message_type(i)->DebugString(0, &contents); + message_type(i)->DebugString(0, &contents, debug_string_options, + /* include_opening_clause */ true); contents.append("\n"); } } for (int i = 0; i < service_count(); i++) { - service(i)->DebugString(&contents); + service(i)->DebugString(&contents, debug_string_options); contents.append("\n"); } @@ -1871,23 +2036,46 @@ string FileDescriptor::DebugString() const { strings::SubstituteAndAppend(&contents, "extend .$0 {\n", containing_type->full_name()); } - extension(i)->DebugString(1, FieldDescriptor::PRINT_LABEL, &contents); + extension(i)->DebugString(1, FieldDescriptor::PRINT_LABEL, &contents, + debug_string_options); } if (extension_count() > 0) contents.append("}\n\n"); + comment_printer.AddPostComment(&contents); + return contents; } string Descriptor::DebugString() const { + DebugStringOptions options; // default options + return DebugStringWithOptions(options); +} + +string Descriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - strings::SubstituteAndAppend(&contents, "message $0", name()); - DebugString(0, &contents); + DebugString(0, &contents, options, /* include_opening_clause */ true); return contents; } -void Descriptor::DebugString(int depth, string *contents) const { +void Descriptor::DebugString(int depth, string *contents, + const DebugStringOptions& + debug_string_options, + bool include_opening_clause) const { + if (options().map_entry()) { + // Do not generate debug string for auto-generated map-entry type. + return; + } string prefix(depth * 2, ' '); ++depth; + + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); + + if (include_opening_clause) { + strings::SubstituteAndAppend(contents, "$0message $1", prefix, name()); + } contents->append(" {\n"); FormatLineOptions(depth, options(), contents); @@ -1909,20 +2097,21 @@ void Descriptor::DebugString(int depth, string *contents) const { for (int i = 0; i < nested_type_count(); i++) { if (groups.count(nested_type(i)) == 0) { - strings::SubstituteAndAppend(contents, "$0 message $1", - prefix, nested_type(i)->name()); - nested_type(i)->DebugString(depth, contents); + nested_type(i)->DebugString(depth, contents, debug_string_options, + /* include_opening_clause */ true); } } for (int i = 0; i < enum_type_count(); i++) { - enum_type(i)->DebugString(depth, contents); + enum_type(i)->DebugString(depth, contents, debug_string_options); } for (int i = 0; i < field_count(); i++) { if (field(i)->containing_oneof() == NULL) { - field(i)->DebugString(depth, FieldDescriptor::PRINT_LABEL, contents); + field(i)->DebugString(depth, FieldDescriptor::PRINT_LABEL, contents, + debug_string_options); } else if (field(i)->containing_oneof()->field(0) == field(i)) { // This is the first field in this oneof, so print the whole oneof. - field(i)->containing_oneof()->DebugString(depth, contents); + field(i)->containing_oneof()->DebugString(depth, contents, + debug_string_options); } } @@ -1943,15 +2132,23 @@ void Descriptor::DebugString(int depth, string *contents) const { prefix, containing_type->full_name()); } extension(i)->DebugString( - depth + 1, FieldDescriptor::PRINT_LABEL, contents); + depth + 1, FieldDescriptor::PRINT_LABEL, contents, + debug_string_options); } if (extension_count() > 0) strings::SubstituteAndAppend(contents, "$0 }\n", prefix); strings::SubstituteAndAppend(contents, "$0}\n", prefix); + comment_printer.AddPostComment(contents); } string FieldDescriptor::DebugString() const { + DebugStringOptions options; // default options + return DebugStringWithOptions(options); +} + +string FieldDescriptor::DebugStringWithOptions( + const DebugStringOptions& debug_string_options) const { string contents; int depth = 0; if (is_extension()) { @@ -1959,35 +2156,55 @@ string FieldDescriptor::DebugString() const { containing_type()->full_name()); depth = 1; } - DebugString(depth, PRINT_LABEL, &contents); + DebugString(depth, PRINT_LABEL, &contents, debug_string_options); if (is_extension()) { contents.append("}\n"); } return contents; } +// The field type string used in FieldDescriptor::DebugString() +string FieldDescriptor::FieldTypeNameDebugString() const { + switch(type()) { + case TYPE_MESSAGE: + return "." + message_type()->full_name(); + case TYPE_ENUM: + return "." + enum_type()->full_name(); + default: + return kTypeToName[type()]; + } +} + void FieldDescriptor::DebugString(int depth, PrintLabelFlag print_label_flag, - string *contents) const { + string *contents, + const DebugStringOptions& + debug_string_options) const { string prefix(depth * 2, ' '); string field_type; - switch (type()) { - case TYPE_MESSAGE: - field_type = "." + message_type()->full_name(); - break; - case TYPE_ENUM: - field_type = "." + enum_type()->full_name(); - break; - default: - field_type = kTypeToName[type()]; + + // Special case map fields. + bool is_map = false; + if (type() == TYPE_MESSAGE && message_type()->options().map_entry()) { + is_map = true; + strings::SubstituteAndAppend( + &field_type, "map<$0, $1>", + message_type()->field(0)->FieldTypeNameDebugString(), + message_type()->field(1)->FieldTypeNameDebugString()); + } else { + field_type = FieldTypeNameDebugString(); } string label; - if (print_label_flag == PRINT_LABEL) { + if (print_label_flag == PRINT_LABEL && !is_map) { label = kLabelToName[this->label()]; label.push_back(' '); } + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); + strings::SubstituteAndAppend(contents, "$0$1$2 $3 = $4", prefix, label, @@ -2015,57 +2232,101 @@ void FieldDescriptor::DebugString(int depth, } if (type() == TYPE_GROUP) { - message_type()->DebugString(depth, contents); + message_type()->DebugString(depth, contents, debug_string_options, + /* include_opening_clause */ false); } else { contents->append(";\n"); } + + comment_printer.AddPostComment(contents); } string OneofDescriptor::DebugString() const { + DebugStringOptions options; // default values + return DebugStringWithOptions(options); +} + +string OneofDescriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - DebugString(0, &contents); + DebugString(0, &contents, options); return contents; } -void OneofDescriptor::DebugString(int depth, string* contents) const { +void OneofDescriptor::DebugString(int depth, string* contents, + const DebugStringOptions& + debug_string_options) const { string prefix(depth * 2, ' '); ++depth; + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); strings::SubstituteAndAppend( contents, "$0 oneof $1 {\n", prefix, name()); for (int i = 0; i < field_count(); i++) { - field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents); + field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents, + debug_string_options); } strings::SubstituteAndAppend(contents, "$0}\n", prefix); + comment_printer.AddPostComment(contents); } string EnumDescriptor::DebugString() const { + DebugStringOptions options; // default values + return DebugStringWithOptions(options); +} + +string EnumDescriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - DebugString(0, &contents); + DebugString(0, &contents, options); return contents; } -void EnumDescriptor::DebugString(int depth, string *contents) const { +void EnumDescriptor::DebugString(int depth, string *contents, + const DebugStringOptions& + debug_string_options) const { string prefix(depth * 2, ' '); ++depth; + + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); + strings::SubstituteAndAppend(contents, "$0enum $1 {\n", prefix, name()); FormatLineOptions(depth, options(), contents); for (int i = 0; i < value_count(); i++) { - value(i)->DebugString(depth, contents); + value(i)->DebugString(depth, contents, debug_string_options); } strings::SubstituteAndAppend(contents, "$0}\n", prefix); + + comment_printer.AddPostComment(contents); } string EnumValueDescriptor::DebugString() const { + DebugStringOptions options; // default values + return DebugStringWithOptions(options); +} + +string EnumValueDescriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - DebugString(0, &contents); + DebugString(0, &contents, options); return contents; } -void EnumValueDescriptor::DebugString(int depth, string *contents) const { +void EnumValueDescriptor::DebugString(int depth, string *contents, + const DebugStringOptions& + debug_string_options) const { string prefix(depth * 2, ' '); + + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); + strings::SubstituteAndAppend(contents, "$0$1 = $2", prefix, name(), number()); @@ -2074,35 +2335,64 @@ void EnumValueDescriptor::DebugString(int depth, string *contents) const { strings::SubstituteAndAppend(contents, " [$0]", formatted_options); } contents->append(";\n"); + + comment_printer.AddPostComment(contents); } string ServiceDescriptor::DebugString() const { + DebugStringOptions options; // default values + return DebugStringWithOptions(options); +} + +string ServiceDescriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - DebugString(&contents); + DebugString(&contents, options); return contents; } -void ServiceDescriptor::DebugString(string *contents) const { +void ServiceDescriptor::DebugString(string *contents, + const DebugStringOptions& + debug_string_options) const { + SourceLocationCommentPrinter + comment_printer(this, /* prefix */ "", debug_string_options); + comment_printer.AddPreComment(contents); + strings::SubstituteAndAppend(contents, "service $0 {\n", name()); FormatLineOptions(1, options(), contents); for (int i = 0; i < method_count(); i++) { - method(i)->DebugString(1, contents); + method(i)->DebugString(1, contents, debug_string_options); } contents->append("}\n"); + + comment_printer.AddPostComment(contents); } string MethodDescriptor::DebugString() const { + DebugStringOptions options; // default values + return DebugStringWithOptions(options); +} + +string MethodDescriptor::DebugStringWithOptions( + const DebugStringOptions& options) const { string contents; - DebugString(0, &contents); + DebugString(0, &contents, options); return contents; } -void MethodDescriptor::DebugString(int depth, string *contents) const { +void MethodDescriptor::DebugString(int depth, string *contents, + const DebugStringOptions& + debug_string_options) const { string prefix(depth * 2, ' '); ++depth; + + SourceLocationCommentPrinter + comment_printer(this, prefix, debug_string_options); + comment_printer.AddPreComment(contents); + strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)", prefix, name(), input_type()->full_name(), @@ -2115,6 +2405,8 @@ void MethodDescriptor::DebugString(int depth, string *contents) const { } else { contents->append(";\n"); } + + comment_printer.AddPostComment(contents); } @@ -2142,6 +2434,11 @@ bool FileDescriptor::GetSourceLocation(const vector& path, return false; } +bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const { + vector path; // empty path for root FileDescriptor + return GetSourceLocation(path, out_location); +} + bool FieldDescriptor::is_packed() const { return is_packable() && (options_ != NULL) && options_->packed(); } @@ -2409,7 +2706,7 @@ class DescriptorBuilder { // Creates a placeholder file. Never returns NULL. This is used when an // import is not found and AllowUnknownDependencies() is enabled. - const FileDescriptor* NewPlaceholderFile(const string& name); + FileDescriptor* NewPlaceholderFile(const string& name); // Calls tables_->AddSymbol() and records an error if it fails. Returns // true if successful or false if failed, though most callers can ignore @@ -2667,9 +2964,24 @@ class DescriptorBuilder { const ServiceDescriptorProto& proto); void ValidateMethodOptions(MethodDescriptor* method, const MethodDescriptorProto& proto); - - void ValidateMapKey(FieldDescriptor* field, - const FieldDescriptorProto& proto); + void ValidateProto3(FileDescriptor* file, + const FileDescriptorProto& proto); + void ValidateProto3Message(Descriptor* message, + const DescriptorProto& proto); + void ValidateProto3Field(FieldDescriptor* field, + const FieldDescriptorProto& proto); + void ValidateProto3Enum(EnumDescriptor* enm, + const EnumDescriptorProto& proto); + + // Returns true if the map entry message is compatible with the + // auto-generated entry message from map fields syntax. + bool ValidateMapEntry(FieldDescriptor* field, + const FieldDescriptorProto& proto); + + // Recursively detects naming conflicts with map entry types for a + // better error message. + void DetectMapConflicts(const Descriptor* message, + const DescriptorProto& proto); }; @@ -2992,19 +3304,9 @@ Symbol DescriptorBuilder::NewPlaceholder(const string& name, } // Create the placeholders. - FileDescriptor* placeholder_file = tables_->Allocate(); - memset(placeholder_file, 0, sizeof(*placeholder_file)); - - placeholder_file->source_code_info_ = &SourceCodeInfo::default_instance(); - - placeholder_file->name_ = - tables_->AllocateString(*placeholder_full_name + ".placeholder.proto"); + FileDescriptor* placeholder_file = NewPlaceholderFile( + *placeholder_full_name + ".placeholder.proto"); placeholder_file->package_ = placeholder_package; - placeholder_file->pool_ = pool_; - placeholder_file->options_ = &FileOptions::default_instance(); - placeholder_file->tables_ = &FileDescriptorTables::kEmpty; - placeholder_file->is_placeholder_ = true; - // All other fields are zero or NULL. if (placeholder_type == PLACEHOLDER_ENUM) { placeholder_file->enum_type_count_ = 1; @@ -3068,7 +3370,7 @@ Symbol DescriptorBuilder::NewPlaceholder(const string& name, } } -const FileDescriptor* DescriptorBuilder::NewPlaceholderFile( +FileDescriptor* DescriptorBuilder::NewPlaceholderFile( const string& name) { FileDescriptor* placeholder = tables_->Allocate(); memset(placeholder, 0, sizeof(*placeholder)); @@ -3078,7 +3380,9 @@ const FileDescriptor* DescriptorBuilder::NewPlaceholderFile( placeholder->pool_ = pool_; placeholder->options_ = &FileOptions::default_instance(); placeholder->tables_ = &FileDescriptorTables::kEmpty; + placeholder->source_code_info_ = &SourceCodeInfo::default_instance(); placeholder->is_placeholder_ = true; + placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2; // All other fields are zero or NULL. return placeholder; @@ -3363,6 +3667,19 @@ const FileDescriptor* DescriptorBuilder::BuildFile( "Missing field: FileDescriptorProto.name."); } + // TODO(liujisi): Report error when the syntax is empty after all the protos + // have added the syntax statement. + if (proto.syntax().empty() || proto.syntax() == "proto2") { + file_->syntax_ = FileDescriptor::SYNTAX_PROTO2; + } else if (proto.syntax() == "proto3") { + file_->syntax_ = FileDescriptor::SYNTAX_PROTO3; + } else { + file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN; + AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, + "Unrecognized syntax: " + proto.syntax()); + } + + result->name_ = tables_->AllocateString(proto.name()); if (proto.has_package()) { result->package_ = tables_->AllocateString(proto.package()); @@ -3506,6 +3823,14 @@ const FileDescriptor* DescriptorBuilder::BuildFile( ValidateFileOptions(result, proto); } + // Additional naming conflict check for map entry types. Only need to check + // this if there are already errors. + if (had_errors_) { + for (int i = 0; i < proto.message_type_size(); ++i) { + DetectMapConflicts(result->message_type(i), proto.message_type(i)); + } + } + if (!unused_dependency_.empty()) { LogUnusedDependency(result); @@ -3621,7 +3946,9 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, // Don't bother with the above optimization for camel-case names since // .proto files that follow the guide shouldn't be using names in this // format, so the optimization wouldn't help much. - result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name())); + result->camelcase_name_ = + tables_->AllocateString(ToCamelCase(proto.name(), + /* lower_first = */ true)); // Some compilers do not allow static_cast directly between two enum types, // so we must cast to int first. @@ -3646,7 +3973,6 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, // Some of these may be filled in when cross-linking. result->containing_type_ = NULL; result->extension_scope_ = NULL; - result->experimental_map_key_ = NULL; result->message_type_ = NULL; result->enum_type_ = NULL; @@ -4472,8 +4798,98 @@ void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file, } } } + if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) { + ValidateProto3(file, proto); + } } +void DescriptorBuilder::ValidateProto3( + FileDescriptor* file, const FileDescriptorProto& proto) { + for (int i = 0; i < file->extension_count(); ++i) { + ValidateProto3Field(file->extensions_ + i, proto.extension(i)); + } + for (int i = 0; i < file->message_type_count(); ++i) { + ValidateProto3Message(file->message_types_ + i, proto.message_type(i)); + } + for (int i = 0; i < file->enum_type_count(); ++i) { + ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i)); + } + if (IsLite(file)) { + AddError(file->name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Lite runtime is not supported in proto3."); + } +} + +void DescriptorBuilder::ValidateProto3Message( + Descriptor* message, const DescriptorProto& proto) { + for (int i = 0; i < message->nested_type_count(); ++i) { + ValidateProto3Message(message->nested_types_ + i, + proto.nested_type(i)); + } + for (int i = 0; i < message->enum_type_count(); ++i) { + ValidateProto3Enum(message->enum_types_ + i, + proto.enum_type(i)); + } + for (int i = 0; i < message->field_count(); ++i) { + ValidateProto3Field(message->fields_ + i, proto.field(i)); + } + for (int i = 0; i < message->extension_count(); ++i) { + ValidateProto3Field(message->extensions_ +i, proto.extension(i)); + } + if (message->extension_range_count() > 0) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Extension ranges are not allowed in proto3."); + } + if (message->options().message_set_wire_format()) { + // Using MessageSet doesn't make sense since we disallow extensions. + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "MessageSet is not supported in proto3."); + } +} + +void DescriptorBuilder::ValidateProto3Field( + FieldDescriptor* field, const FieldDescriptorProto& proto) { + if (field->is_extension() && + !AllowedExtendeeInProto3(field->containing_type()->full_name())) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Extensions in proto3 are only allowed for defining options."); + } + if (field->is_required()) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "Required fields are not allowed in proto3."); + } + if (field->has_default_value()) { + AddError( + field->full_name(), proto, DescriptorPool::ErrorCollector::OTHER, + "Explicit default values are not allowed in proto3."); + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && + field->enum_type() && + field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_PROTO3) { + // Proto3 messages can only use Proto3 enum types; otherwise we can't + // guarantee that the default value is zero. + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "Enum type \"" + field->enum_type()->full_name() + + "\" is not a proto3 enum, but is used in \"" + + field->containing_type()->full_name() + + "\" which is a proto3 message type."); + } +} + +void DescriptorBuilder::ValidateProto3Enum( + EnumDescriptor* enm, const EnumDescriptorProto& proto) { + if (enm->value_count() > 0 && enm->value(0)->number() != 0) { + AddError( + enm->full_name(), proto, DescriptorPool::ErrorCollector::OTHER, + "The first enum value must be zero in proto3."); + } +} void DescriptorBuilder::ValidateMessageOptions(Descriptor* message, const DescriptorProto& proto) { @@ -4499,10 +4915,6 @@ void DescriptorBuilder::ValidateMessageOptions(Descriptor* message, void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, const FieldDescriptorProto& proto) { - if (field->options().has_experimental_map_key()) { - ValidateMapKey(field, proto); - } - // Only message type fields may be lazy. if (field->options().lazy()) { if (field->type() != FieldDescriptor::TYPE_MESSAGE) { @@ -4551,6 +4963,17 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, "a lite type, but the reverse is allowed."); } + // Validate map types. + if (field->type() == FieldDescriptor::TYPE_MESSAGE && + field->message_type()->options().map_entry()) { + if (!ValidateMapEntry(field, proto)) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::OTHER, + "map_entry should not be set explicitly. Use map instead."); + } + } + } void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm, @@ -4608,57 +5031,127 @@ void DescriptorBuilder::ValidateMethodOptions(MethodDescriptor* /* method */, // Nothing to do so far. } -void DescriptorBuilder::ValidateMapKey(FieldDescriptor* field, - const FieldDescriptorProto& proto) { - if (!field->is_repeated()) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "map type is only allowed for repeated fields."); - return; +bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field, + const FieldDescriptorProto& proto) { + const Descriptor* message = field->message_type(); + if (// Must not contain extensions, extension range or nested message or + // enums + message->extension_count() != 0 || + field->label() != FieldDescriptor::LABEL_REPEATED || + message->extension_range_count() != 0 || + message->nested_type_count() != 0 || message->enum_type_count() != 0 || + // Must contain exactly two fields + message->field_count() != 2 || + // Field name and message name must match + message->name() != ToCamelCase(field->name(), false) + "Entry" || + // Entry message must be in the same containing type of the field. + field->containing_type() != message->containing_type()) { + return false; } - if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "map type is only allowed for fields with a message type."); - return; + const FieldDescriptor* key = message->field(0); + const FieldDescriptor* value = message->field(1); + if (key->label() != FieldDescriptor::LABEL_OPTIONAL || key->number() != 1 || + key->name() != "key") { + return false; + } + if (value->label() != FieldDescriptor::LABEL_OPTIONAL || + value->number() != 2 || value->name() != "value") { + return false; } - const Descriptor* item_type = field->message_type(); - if (item_type == NULL) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "Could not find field type."); - return; + // Check key types are legal. + switch (key->type()) { + case FieldDescriptor::TYPE_ENUM: + AddError( + field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Key in map fields cannot be enum types."); + break; + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_BYTES: + AddError( + field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Key in map fields cannot be float/double, bytes or message types."); + break; + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + // Legal cases + break; + // Do not add a default, so that the compiler will complian when new types + // are added. } - // Find the field in item_type named by "experimental_map_key" - const string& key_name = field->options().experimental_map_key(); - const Symbol key_symbol = LookupSymbol( - key_name, - // We append ".key_name" to the containing type's name since - // LookupSymbol() searches for peers of the supplied name, not - // children of the supplied name. - item_type->full_name() + "." + key_name); + return true; +} - if (key_symbol.IsNull() || key_symbol.field_descriptor->is_extension()) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "Could not find field named \"" + key_name + "\" in type \"" + - item_type->full_name() + "\"."); - return; +void DescriptorBuilder::DetectMapConflicts(const Descriptor* message, + const DescriptorProto& proto) { + map seen_types; + for (int i = 0; i < message->nested_type_count(); ++i) { + const Descriptor* nested = message->nested_type(i); + pair::iterator, bool> result = + seen_types.insert(make_pair(nested->name(), nested)); + if (!result.second) { + if (result.first->second->options().map_entry() || + nested->options().map_entry()) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Expanded map entry type " + nested->name() + + " conflicts with an existing nested message type."); + } + } + // Recursively test on the nested types. + DetectMapConflicts(message->nested_type(i), proto.nested_type(i)); + } + // Check for conflicted field names. + for (int i = 0; i < message->field_count(); ++i) { + const FieldDescriptor* field = message->field(i); + map::iterator iter = + seen_types.find(field->name()); + if (iter != seen_types.end() && iter->second->options().map_entry()) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Expanded map entry type " + iter->second->name() + + " conflicts with an existing field."); + } } - const FieldDescriptor* key_field = key_symbol.field_descriptor; - - if (key_field->is_repeated()) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "map_key must not name a repeated field."); - return; + // Check for conflicted enum names. + for (int i = 0; i < message->enum_type_count(); ++i) { + const EnumDescriptor* enum_desc = message->enum_type(i); + map::iterator iter = + seen_types.find(enum_desc->name()); + if (iter != seen_types.end() && iter->second->options().map_entry()) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Expanded map entry type " + iter->second->name() + + " conflicts with an existing enum type."); + } } - - if (key_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, - "map key must name a scalar or string field."); - return; + // Check for conflicted oneof names. + for (int i = 0; i < message->oneof_decl_count(); ++i) { + const OneofDescriptor* oneof_desc = message->oneof_decl(i); + map::iterator iter = + seen_types.find(oneof_desc->name()); + if (iter != seen_types.end() && iter->second->options().map_entry()) { + AddError(message->full_name(), proto, + DescriptorPool::ErrorCollector::NAME, + "Expanded map entry type " + iter->second->name() + + " conflicts with an existing oneof type."); + } } - - field->experimental_map_key_ = key_field; } diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 68013f8e..b7ea756c 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -104,6 +104,11 @@ class FileDescriptorTables; // Defined in unknown_field_set.h. class UnknownField; +// Defined in generated_message_reflection.h. +namespace internal { + class GeneratedMessageReflection; +} + // NB, all indices are zero-based. struct SourceLocation { int start_line; @@ -118,6 +123,20 @@ struct SourceLocation { string trailing_comments; }; +// Options when generating machine-parsable output from a descriptor with +// DebugString(). +struct DebugStringOptions { + // include original user comments as recorded in SourceLocation entries. N.B. + // that this must be |false| by default: several other pieces of code (for + // example, the C++ code generation for fields in the proto compiler) rely on + // DebugString() output being unobstructed by user comments. + bool include_comments; + + DebugStringOptions() + : include_comments(false) + {} +}; + // Describes a type of protocol message, or a particular group within a // message. To obtain the Descriptor for a given message object, call // Message::GetDescriptor(). Generated message classes also have a @@ -162,6 +181,10 @@ class LIBPROTOBUF_EXPORT Descriptor { // will be suitable for re-parsing. string DebugString() const; + // Similar to DebugString(), but additionally takes options (e.g., + // include original user comments in output). + string DebugStringWithOptions(const DebugStringOptions& options) const; + // Returns true if this is a placeholder for an unknown type. This will // only be the case if this descriptor comes from a DescriptorPool // with AllowUnknownDependencies() set. @@ -282,8 +305,12 @@ class LIBPROTOBUF_EXPORT Descriptor { typedef MessageOptions OptionsType; // Internal version of DebugString; controls the level of indenting for - // correct depth - void DebugString(int depth, string *contents) const; + // correct depth. Takes |options| to control debug-string options, and + // |include_opening_clause| to indicate whether the "message ... " part of the + // clause has already been generated (this varies depending on context). + void DebugString(int depth, string *contents, + const DebugStringOptions& options, + bool include_opening_clause) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -513,12 +540,6 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // returns null. const EnumDescriptor* enum_type() const; - // EXPERIMENTAL; DO NOT USE. - // If this field is a map field, experimental_map_key() is the field - // that is the key for this map. - // experimental_map_key()->containing_type() is the same as message_type(). - const FieldDescriptor* experimental_map_key() const; - // Get the FieldOptions for this field. This includes things listed in // square brackets after the field definition. E.g., the field: // optional string text = 1 [ctype=CORD]; @@ -533,6 +554,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + // Helper method to get the CppType for a particular Type. static CppType TypeToCppType(Type type); @@ -558,13 +582,16 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // See Descriptor::DebugString(). enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL }; void DebugString(int depth, PrintLabelFlag print_label_flag, - string* contents) const; + string* contents, const DebugStringOptions& options) const; // formats the default value appropriately and returns it as a string. // Must have a default value to call this. If quote_string_type is true, then // types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped. string DefaultValueAsString(bool quote_string_type) const; + // Helper function that returns the field type name for DebugString. + string FieldTypeNameDebugString() const; + // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. void GetLocationPath(vector* output) const; @@ -584,7 +611,6 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { const Descriptor* extension_scope_; const Descriptor* message_type_; const EnumDescriptor* enum_type_; - const FieldDescriptor* experimental_map_key_; const FieldOptions* options_; // IMPORTANT: If you add a new field, make sure to search for all instances // of Allocate() and AllocateArray() in @@ -645,6 +671,9 @@ class LIBPROTOBUF_EXPORT OneofDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + // Source Location --------------------------------------------------- // Updates |*out_location| to the source location of the complete @@ -654,7 +683,8 @@ class LIBPROTOBUF_EXPORT OneofDescriptor { private: // See Descriptor::DebugString(). - void DebugString(int depth, string* contents) const; + void DebugString(int depth, string* contents, + const DebugStringOptions& options) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -723,6 +753,10 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + + // Returns true if this is a placeholder for an unknown enum. This will // only be the case if this descriptor comes from a DescriptorPool // with AllowUnknownDependencies() set. @@ -738,8 +772,21 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { private: typedef EnumOptions OptionsType; + // Looks up a value by number. If the value does not exist, dynamically + // creates a new EnumValueDescriptor for that value, assuming that it was + // unknown. If a new descriptor is created, this is done in a thread-safe way, + // and future calls will return the same value descriptor pointer. + // + // This is private but is used by GeneratedMessageReflection (which is + // friended below) to return a valid EnumValueDescriptor from GetEnum() when + // this feature is enabled. + const EnumValueDescriptor* + FindValueByNumberCreatingIfUnknown(int number) const; + + // See Descriptor::DebugString(). - void DebugString(int depth, string *contents) const; + void DebugString(int depth, string *contents, + const DebugStringOptions& options) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -769,6 +816,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { friend class FieldDescriptor; friend class EnumValueDescriptor; friend class FileDescriptor; + friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); }; @@ -806,6 +854,10 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + + // Source Location --------------------------------------------------- // Updates |*out_location| to the source location of the complete @@ -817,7 +869,8 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { typedef EnumValueOptions OptionsType; // See Descriptor::DebugString(). - void DebugString(int depth, string *contents) const; + void DebugString(int depth, string *contents, + const DebugStringOptions& options) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -836,6 +889,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { EnumValueDescriptor() {} friend class DescriptorBuilder; friend class EnumDescriptor; + friend class FileDescriptorTables; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor); }; @@ -876,6 +930,10 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + + // Source Location --------------------------------------------------- // Updates |*out_location| to the source location of the complete @@ -887,7 +945,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor { typedef ServiceOptions OptionsType; // See Descriptor::DebugString(). - void DebugString(string *contents) const; + void DebugString(string *contents, const DebugStringOptions& options) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -945,6 +1003,10 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + + // Source Location --------------------------------------------------- // Updates |*out_location| to the source location of the complete @@ -956,7 +1018,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { typedef MethodOptions OptionsType; // See Descriptor::DebugString(). - void DebugString(int depth, string *contents) const; + void DebugString(int depth, string *contents, + const DebugStringOptions& options) const; // Walks up the descriptor tree to generate the source location path // to this descriptor from the file root. @@ -1052,6 +1115,15 @@ class LIBPROTOBUF_EXPORT FileDescriptor { // message. const FileOptions& options() const; + // Syntax of this file. + enum Syntax { + SYNTAX_UNKNOWN = 0, + SYNTAX_PROTO2 = 2, + SYNTAX_PROTO3 = 3, + }; + Syntax syntax() const; + static const char* SyntaxName(Syntax syntax); + // Find a top-level message type by name. Returns NULL if not found. const Descriptor* FindMessageTypeByName(const string& name) const; // Find a top-level enum type by name. Returns NULL if not found. @@ -1082,11 +1154,18 @@ class LIBPROTOBUF_EXPORT FileDescriptor { // See Descriptor::DebugString(). string DebugString() const; + // See Descriptor::DebugStringWithOptions(). + string DebugStringWithOptions(const DebugStringOptions& options) const; + // Returns true if this is a placeholder for an unknown file. This will // only be the case if this descriptor comes from a DescriptorPool // with AllowUnknownDependencies() set. bool is_placeholder() const; + // Updates |*out_location| to the source location of the complete extent of + // this file declaration (namely, the empty path). + bool GetSourceLocation(SourceLocation* out_location) const; + private: // Source Location --------------------------------------------------- @@ -1116,6 +1195,7 @@ class LIBPROTOBUF_EXPORT FileDescriptor { int service_count_; ServiceDescriptor* services_; int extension_count_; + Syntax syntax_; bool is_placeholder_; FieldDescriptor* extensions_; const FileOptions* options_; @@ -1394,6 +1474,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool { friend class ServiceDescriptor; friend class FileDescriptor; friend class DescriptorBuilder; + friend class FileDescriptorTables; // Return true if the given name is a sub-symbol of any non-package // descriptor that already exists in the descriptor pool. (The full @@ -1494,8 +1575,6 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, index_in_oneof, int) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, extension_scope, const Descriptor*) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*) -PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key, - const FieldDescriptor*) PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool) PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 ) @@ -1679,6 +1758,10 @@ inline const FileDescriptor* FileDescriptor::weak_dependency( return dependencies_[weak_dependencies_[index]]; } +inline FileDescriptor::Syntax FileDescriptor::syntax() const { + return syntax_; +} + // Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because fields_ is actually an array // of pointers rather than the usual array of objects. inline const FieldDescriptor* OneofDescriptor::field(int index) const { diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index c3aa2fb6..4fe01ce3 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -108,13 +108,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { FileDescriptorSet::default_instance_, FileDescriptorSet_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(FileDescriptorSet)); + sizeof(FileDescriptorSet), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_)); FileDescriptorProto_descriptor_ = file->message_type(1); - static const int FileDescriptorProto_offsets_[11] = { + static const int FileDescriptorProto_offsets_[12] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, dependency_), @@ -126,6 +127,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, extension_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, source_code_info_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, syntax_), }; FileDescriptorProto_reflection_ = new ::google::protobuf::internal::GeneratedMessageReflection( @@ -133,11 +135,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { FileDescriptorProto::default_instance_, FileDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(FileDescriptorProto)); + sizeof(FileDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_)); DescriptorProto_descriptor_ = file->message_type(2); static const int DescriptorProto_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), @@ -155,11 +158,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { DescriptorProto::default_instance_, DescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(DescriptorProto)); + sizeof(DescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_)); DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0); static const int DescriptorProto_ExtensionRange_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_), @@ -171,11 +175,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { DescriptorProto_ExtensionRange::default_instance_, DescriptorProto_ExtensionRange_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(DescriptorProto_ExtensionRange)); + sizeof(DescriptorProto_ExtensionRange), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_)); FieldDescriptorProto_descriptor_ = file->message_type(3); static const int FieldDescriptorProto_offsets_[9] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), @@ -194,11 +199,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { FieldDescriptorProto::default_instance_, FieldDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(FieldDescriptorProto)); + sizeof(FieldDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_)); FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0); FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1); OneofDescriptorProto_descriptor_ = file->message_type(4); @@ -211,11 +217,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { OneofDescriptorProto::default_instance_, OneofDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(OneofDescriptorProto)); + sizeof(OneofDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_)); EnumDescriptorProto_descriptor_ = file->message_type(5); static const int EnumDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_), @@ -228,11 +235,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { EnumDescriptorProto::default_instance_, EnumDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(EnumDescriptorProto)); + sizeof(EnumDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_)); EnumValueDescriptorProto_descriptor_ = file->message_type(6); static const int EnumValueDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_), @@ -245,11 +253,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { EnumValueDescriptorProto::default_instance_, EnumValueDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(EnumValueDescriptorProto)); + sizeof(EnumValueDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_)); ServiceDescriptorProto_descriptor_ = file->message_type(7); static const int ServiceDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_), @@ -262,11 +271,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { ServiceDescriptorProto::default_instance_, ServiceDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(ServiceDescriptorProto)); + sizeof(ServiceDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_)); MethodDescriptorProto_descriptor_ = file->message_type(8); static const int MethodDescriptorProto_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_), @@ -280,11 +290,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { MethodDescriptorProto::default_instance_, MethodDescriptorProto_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(MethodDescriptorProto)); + sizeof(MethodDescriptorProto), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_)); FileOptions_descriptor_ = file->message_type(9); static const int FileOptions_offsets_[12] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), @@ -306,17 +317,19 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { FileOptions::default_instance_, FileOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(FileOptions)); + sizeof(FileOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_)); FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0); MessageOptions_descriptor_ = file->message_type(10); - static const int MessageOptions_offsets_[4] = { + static const int MessageOptions_offsets_[5] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, message_set_wire_format_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, no_standard_descriptor_accessor_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, deprecated_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, map_entry_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, uninterpreted_option_), }; MessageOptions_reflection_ = @@ -325,18 +338,18 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { MessageOptions::default_instance_, MessageOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(MessageOptions)); + sizeof(MessageOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_)); FieldOptions_descriptor_ = file->message_type(11); - static const int FieldOptions_offsets_[7] = { + static const int FieldOptions_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, lazy_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, weak_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_), }; @@ -346,11 +359,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { FieldOptions::default_instance_, FieldOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(FieldOptions)); + sizeof(FieldOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_)); FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); EnumOptions_descriptor_ = file->message_type(12); static const int EnumOptions_offsets_[3] = { @@ -364,11 +378,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { EnumOptions::default_instance_, EnumOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(EnumOptions)); + sizeof(EnumOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_)); EnumValueOptions_descriptor_ = file->message_type(13); static const int EnumValueOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_), @@ -380,11 +395,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { EnumValueOptions::default_instance_, EnumValueOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(EnumValueOptions)); + sizeof(EnumValueOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_)); ServiceOptions_descriptor_ = file->message_type(14); static const int ServiceOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_), @@ -396,11 +412,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { ServiceOptions::default_instance_, ServiceOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(ServiceOptions)); + sizeof(ServiceOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_)); MethodOptions_descriptor_ = file->message_type(15); static const int MethodOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_), @@ -412,11 +429,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { MethodOptions::default_instance_, MethodOptions_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _unknown_fields_), + -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(MethodOptions)); + sizeof(MethodOptions), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_)); UninterpretedOption_descriptor_ = file->message_type(16); static const int UninterpretedOption_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_), @@ -433,11 +451,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { UninterpretedOption::default_instance_, UninterpretedOption_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(UninterpretedOption)); + sizeof(UninterpretedOption), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_)); 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_), @@ -449,11 +468,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { UninterpretedOption_NamePart::default_instance_, UninterpretedOption_NamePart_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(UninterpretedOption_NamePart)); + sizeof(UninterpretedOption_NamePart), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_)); SourceCodeInfo_descriptor_ = file->message_type(17); static const int SourceCodeInfo_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_), @@ -464,11 +484,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { SourceCodeInfo::default_instance_, SourceCodeInfo_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(SourceCodeInfo)); + sizeof(SourceCodeInfo), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_)); SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0); static const int SourceCodeInfo_Location_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_), @@ -482,11 +503,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { SourceCodeInfo_Location::default_instance_, SourceCodeInfo_Location_offsets_, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _has_bits_[0]), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _unknown_fields_), + -1, -1, ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), - sizeof(SourceCodeInfo_Location)); + sizeof(SourceCodeInfo_Location), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_)); } namespace { @@ -600,7 +622,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "\n google/protobuf/descriptor.proto\022\017goog" "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file" "\030\001 \003(\0132$.google.protobuf.FileDescriptorP" - "roto\"\313\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001" + "roto\"\333\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001" "(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022" "\031\n\021public_dependency\030\n \003(\005\022\027\n\017weak_depen" "dency\030\013 \003(\005\0226\n\014message_type\030\004 \003(\0132 .goog" @@ -611,104 +633,104 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "\0132%.google.protobuf.FieldDescriptorProto" "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File" "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog" - "le.protobuf.SourceCodeInfo\"\344\003\n\017Descripto" - "rProto\022\014\n\004name\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.go" - "ogle.protobuf.FieldDescriptorProto\0228\n\tex" - "tension\030\006 \003(\0132%.google.protobuf.FieldDes" - "criptorProto\0225\n\013nested_type\030\003 \003(\0132 .goog" - "le.protobuf.DescriptorProto\0227\n\tenum_type" - "\030\004 \003(\0132$.google.protobuf.EnumDescriptorP" - "roto\022H\n\017extension_range\030\005 \003(\0132/.google.p" - "rotobuf.DescriptorProto.ExtensionRange\0229" - "\n\noneof_decl\030\010 \003(\0132%.google.protobuf.One" - "ofDescriptorProto\0220\n\007options\030\007 \001(\0132\037.goo" - "gle.protobuf.MessageOptions\032,\n\016Extension" - "Range\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024Fi" - "eldDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006numb" - "er\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobu" - "f.FieldDescriptorProto.Label\0228\n\004type\030\005 \001" - "(\0162*.google.protobuf.FieldDescriptorProt" - "o.Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 " - "\001(\t\022\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_inde" - "x\030\t \001(\005\022.\n\007options\030\010 \001(\0132\035.google.protob" - "uf.FieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020" - "\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYP" - "E_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED" - "64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n" - "\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_M" - "ESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020" - "\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rT" - "YPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_" - "SINT64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n" - "\016LABEL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n" - "\024OneofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023" - "EnumDescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005val" - "ue\030\002 \003(\0132).google.protobuf.EnumValueDesc" - "riptorProto\022-\n\007options\030\003 \001(\0132\034.google.pr" - "otobuf.EnumOptions\"l\n\030EnumValueDescripto" - "rProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007" - "options\030\003 \001(\0132!.google.protobuf.EnumValu" - "eOptions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004n" - "ame\030\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.proto" - "buf.MethodDescriptorProto\0220\n\007options\030\003 \001" - "(\0132\037.google.protobuf.ServiceOptions\"\177\n\025M" - "ethodDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\nin" - "put_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007o" - "ptions\030\004 \001(\0132\036.google.protobuf.MethodOpt" - "ions\"\253\004\n\013FileOptions\022\024\n\014java_package\030\001 \001" - "(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023java" - "_multiple_files\030\n \001(\010:\005false\022,\n\035java_gen" - "erate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026ja" - "va_string_check_utf8\030\033 \001(\010:\005false\022F\n\014opt" - "imize_for\030\t \001(\0162).google.protobuf.FileOp" - "tions.OptimizeMode:\005SPEED\022\022\n\ngo_package\030" - "\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fals" - "e\022$\n\025java_generic_services\030\021 \001(\010:\005false\022" - "\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n\nd" - "eprecated\030\027 \001(\010:\005false\022C\n\024uninterpreted_" - "option\030\347\007 \003(\0132$.google.protobuf.Uninterp" - "retedOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r" - "\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200" - "\200\002\"\323\001\n\016MessageOptions\022&\n\027message_set_wir" - "e_format\030\001 \001(\010:\005false\022.\n\037no_standard_des" - "criptor_accessor\030\002 \001(\010:\005false\022\031\n\ndepreca" - "ted\030\003 \001(\010:\005false\022C\n\024uninterpreted_option" - "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO" - "ption*\t\010\350\007\020\200\200\200\200\002\"\276\002\n\014FieldOptions\022:\n\005cty" - "pe\030\001 \001(\0162#.google.protobuf.FieldOptions." - "CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 " - "\001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\034\n" - "\024experimental_map_key\030\t \001(\t\022\023\n\004weak\030\n \001(" - "\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132" - "$.google.protobuf.UninterpretedOption\"/\n" - "\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_P" - "IECE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013all" - "ow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fals" - "e\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.googl" - "e.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200" - "\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(" - "\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132" - "$.google.protobuf.UninterpretedOption*\t\010" - "\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated" - "\030! \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007" + "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001" + "(\t\"\344\003\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005" + "field\030\002 \003(\0132%.google.protobuf.FieldDescr" + "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p" + "rotobuf.FieldDescriptorProto\0225\n\013nested_t" + "ype\030\003 \003(\0132 .google.protobuf.DescriptorPr" + "oto\0227\n\tenum_type\030\004 \003(\0132$.google.protobuf" + ".EnumDescriptorProto\022H\n\017extension_range\030" + "\005 \003(\0132/.google.protobuf.DescriptorProto." + "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo" + "gle.protobuf.OneofDescriptorProto\0220\n\007opt" + "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti" + "ons\032,\n\016ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003" + "end\030\002 \001(\005\"\251\005\n\024FieldDescriptorProto\022\014\n\004na" + "me\030\001 \001(\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162" + "+.google.protobuf.FieldDescriptorProto.L" + "abel\0228\n\004type\030\005 \001(\0162*.google.protobuf.Fie" + "ldDescriptorProto.Type\022\021\n\ttype_name\030\006 \001(" + "\t\022\020\n\010extendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001" + "(\t\022\023\n\013oneof_index\030\t \001(\005\022.\n\007options\030\010 \001(\013" + "2\035.google.protobuf.FieldOptions\"\266\002\n\004Type" + "\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYP" + "E_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32" + "\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r" + "\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_G" + "ROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014" + "\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE" + "_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_S" + "INT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LAB" + "EL_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LAB" + "EL_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n" + "\004name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004n" + "ame\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protob" + "uf.EnumValueDescriptorProto\022-\n\007options\030\003" + " \001(\0132\034.google.protobuf.EnumOptions\"l\n\030En" + "umValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006" + "number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.p" + "rotobuf.EnumValueOptions\"\220\001\n\026ServiceDesc" + "riptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(" + "\0132&.google.protobuf.MethodDescriptorProt" + "o\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Ser" + "viceOptions\"\177\n\025MethodDescriptorProto\022\014\n\004" + "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output" + "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr" + "otobuf.MethodOptions\"\253\004\n\013FileOptions\022\024\n\014" + "java_package\030\001 \001(\t\022\034\n\024java_outer_classna" + "me\030\010 \001(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005f" + "alse\022,\n\035java_generate_equals_and_hash\030\024 " + "\001(\010:\005false\022%\n\026java_string_check_utf8\030\033 \001" + "(\010:\005false\022F\n\014optimize_for\030\t \001(\0162).google" + ".protobuf.FileOptions.OptimizeMode:\005SPEE" + "D\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_generic_serv" + "ices\030\020 \001(\010:\005false\022$\n\025java_generic_servic" + "es\030\021 \001(\010:\005false\022\"\n\023py_generic_services\030\022" + " \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005false\022C" + "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" + "rotobuf.UninterpretedOption\":\n\014OptimizeM" + "ode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RU" + "NTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n" + "\027message_set_wire_format\030\001 \001(\010:\005false\022.\n" + "\037no_standard_descriptor_accessor\030\002 \001(\010:\005" + "false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_" + "entry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "*\t\010\350\007\020\200\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005ctype\030\001 " + "\001(\0162#.google.protobuf.FieldOptions.CType" + ":\006STRING\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005" + "false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak" + "\030\n \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007" " \003(\0132$.google.protobuf.UninterpretedOpti" - "on*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprec" - "ated\030! \001(\010:\005false\022C\n\024uninterpreted_optio" - "n\030\347\007 \003(\0132$.google.protobuf.Uninterpreted" - "Option*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOptio" - "n\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uninte" - "rpretedOption.NamePart\022\030\n\020identifier_val" - "ue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022" - "negative_int_value\030\005 \001(\003\022\024\n\014double_value" - "\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregat" - "e_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001" - " \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\261\001\n\016SourceCod" - "eInfo\022:\n\010location\030\001 \003(\0132(.google.protobu" - "f.SourceCodeInfo.Location\032c\n\010Location\022\020\n" - "\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lea" - "ding_comments\030\003 \001(\t\022\031\n\021trailing_comments" - "\030\004 \001(\tB)\n\023com.google.protobufB\020Descripto" - "rProtosH\001", 4449); + "on\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STR" + "ING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023" + "\n\013allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:" + "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption*\t\010\350\007" + "\020\200\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated" + "\030\001 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007" + " \003(\0132$.google.protobuf.UninterpretedOpti" + "on*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepre" + "cated\030! \001(\010:\005false\022C\n\024uninterpreted_opti" + "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete" + "dOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\nd" + "eprecated\030! \001(\010:\005false\022C\n\024uninterpreted_" + "option\030\347\007 \003(\0132$.google.protobuf.Uninterp" + "retedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Uninterpreted" + "Option\022;\n\004name\030\002 \003(\0132-.google.protobuf.U" + "ninterpretedOption.NamePart\022\030\n\020identifie" + "r_value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(" + "\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_" + "value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017agg" + "regate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_p" + "art\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\261\001\n\016Sour" + "ceCodeInfo\022:\n\010location\030\001 \003(\0132(.google.pr" + "otobuf.SourceCodeInfo.Location\032c\n\010Locati" + "on\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030" + "\n\020leading_comments\030\003 \001(\t\022\031\n\021trailing_com" + "ments\030\004 \001(\tB)\n\023com.google.protobufB\020Desc" + "riptorProtosH\001", 4454); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -770,16 +792,26 @@ const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER FileDescriptorSet::FileDescriptorSet() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorSet) } +FileDescriptorSet::FileDescriptorSet(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + file_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorSet) +} + void FileDescriptorSet::InitAsDefaultInstance() { } FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorSet) @@ -796,10 +828,20 @@ FileDescriptorSet::~FileDescriptorSet() { } void FileDescriptorSet::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void FileDescriptorSet::ArenaDtor(void* object) { + FileDescriptorSet* _this = reinterpret_cast< FileDescriptorSet* >(object); + (void)_this; +} +void FileDescriptorSet::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FileDescriptorSet::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -817,14 +859,16 @@ const FileDescriptorSet& FileDescriptorSet::default_instance() { FileDescriptorSet* FileDescriptorSet::default_instance_ = NULL; -FileDescriptorSet* FileDescriptorSet::New() const { - return new FileDescriptorSet; +FileDescriptorSet* FileDescriptorSet::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void FileDescriptorSet::Clear() { file_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool FileDescriptorSet::MergePartialFromCodedStream( @@ -882,7 +926,7 @@ void FileDescriptorSet::SerializeWithCachedSizes( 1, this->file(i), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -899,7 +943,7 @@ void FileDescriptorSet::SerializeWithCachedSizes( 1, this->file(i), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -918,7 +962,7 @@ int FileDescriptorSet::ByteSize() const { this->file(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -944,7 +988,9 @@ void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) { void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { GOOGLE_CHECK_NE(&from, this); file_.MergeFrom(from.file_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void FileDescriptorSet::CopyFrom(const ::google::protobuf::Message& from) { @@ -966,13 +1012,27 @@ bool FileDescriptorSet::IsInitialized() const { } void FileDescriptorSet::Swap(FileDescriptorSet* other) { - if (other != this) { - 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 { + FileDescriptorSet temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void FileDescriptorSet::UnsafeArenaSwap(FileDescriptorSet* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) { + 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 FileDescriptorSet::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -997,21 +1057,38 @@ const int FileDescriptorProto::kServiceFieldNumber; const int FileDescriptorProto::kExtensionFieldNumber; const int FileDescriptorProto::kOptionsFieldNumber; const int FileDescriptorProto::kSourceCodeInfoFieldNumber; +const int FileDescriptorProto::kSyntaxFieldNumber; #endif // !_MSC_VER FileDescriptorProto::FileDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorProto) } +FileDescriptorProto::FileDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + dependency_(arena), + public_dependency_(arena), + weak_dependency_(arena), + message_type_(arena), + enum_type_(arena), + service_(arena), + extension_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorProto) +} + void FileDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FileOptions*>(&::google::protobuf::FileOptions::default_instance()); source_code_info_ = const_cast< ::google::protobuf::SourceCodeInfo*>(&::google::protobuf::SourceCodeInfo::default_instance()); } FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorProto) @@ -1020,10 +1097,11 @@ FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) void FileDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; source_code_info_ = NULL; + syntax_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -1033,18 +1111,25 @@ FileDescriptorProto::~FileDescriptorProto() { } void FileDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; - } - if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete package_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + package_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + syntax_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; delete source_code_info_; } } +void FileDescriptorProto::ArenaDtor(void* object) { + FileDescriptorProto* _this = reinterpret_cast< FileDescriptorProto* >(object); + (void)_this; +} +void FileDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FileDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1062,30 +1147,29 @@ const FileDescriptorProto& FileDescriptorProto::default_instance() { FileDescriptorProto* FileDescriptorProto::default_instance_ = NULL; -FileDescriptorProto* FileDescriptorProto::New() const { - return new FileDescriptorProto; +FileDescriptorProto* FileDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void FileDescriptorProto::Clear() { if (_has_bits_[0 / 32] & 3) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_package()) { - if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_->clear(); - } + package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } } - if (_has_bits_[8 / 32] & 1536) { + if (_has_bits_[8 / 32] & 3584) { if (has_options()) { if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); } if (has_source_code_info()) { if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); } + if (has_syntax()) { + syntax_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + } } dependency_.Clear(); public_dependency_.Clear(); @@ -1095,7 +1179,9 @@ void FileDescriptorProto::Clear() { service_.Clear(); extension_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool FileDescriptorProto::MergePartialFromCodedStream( @@ -1116,7 +1202,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.FileDescriptorProto.name"); } else { goto handle_unusual; } @@ -1133,7 +1219,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->package().data(), this->package().length(), ::google::protobuf::internal::WireFormat::PARSE, - "package"); + "google.protobuf.FileDescriptorProto.package"); } else { goto handle_unusual; } @@ -1151,7 +1237,7 @@ bool FileDescriptorProto::MergePartialFromCodedStream( this->dependency(this->dependency_size() - 1).data(), this->dependency(this->dependency_size() - 1).length(), ::google::protobuf::internal::WireFormat::PARSE, - "dependency"); + "google.protobuf.FileDescriptorProto.dependency"); } else { goto handle_unusual; } @@ -1276,6 +1362,23 @@ bool FileDescriptorProto::MergePartialFromCodedStream( goto handle_unusual; } if (input->ExpectTag(88)) goto parse_weak_dependency; + if (input->ExpectTag(98)) goto parse_syntax; + break; + } + + // optional string syntax = 12; + case 12: { + if (tag == 98) { + parse_syntax: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_syntax())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->syntax().data(), this->syntax().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.FileDescriptorProto.syntax"); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1310,7 +1413,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.FileDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -1320,7 +1423,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->package().data(), this->package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "package"); + "google.protobuf.FileDescriptorProto.package"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->package(), output); } @@ -1330,7 +1433,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->dependency(i).data(), this->dependency(i).length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "dependency"); + "google.protobuf.FileDescriptorProto.dependency"); ::google::protobuf::internal::WireFormatLite::WriteString( 3, this->dependency(i), output); } @@ -1383,7 +1486,17 @@ void FileDescriptorProto::SerializeWithCachedSizes( 11, this->weak_dependency(i), output); } - if (!unknown_fields().empty()) { + // optional string syntax = 12; + if (has_syntax()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->syntax().data(), this->syntax().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FileDescriptorProto.syntax"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 12, this->syntax(), output); + } + + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -1398,7 +1511,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.FileDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -1409,7 +1522,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->package().data(), this->package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "package"); + "google.protobuf.FileDescriptorProto.package"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 2, this->package(), target); @@ -1420,7 +1533,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->dependency(i).data(), this->dependency(i).length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "dependency"); + "google.protobuf.FileDescriptorProto.dependency"); target = ::google::protobuf::internal::WireFormatLite:: WriteStringToArray(3, this->dependency(i), target); } @@ -1479,7 +1592,18 @@ void FileDescriptorProto::SerializeWithCachedSizes( WriteInt32ToArray(11, this->weak_dependency(i), target); } - if (!unknown_fields().empty()) { + // optional string syntax = 12; + if (has_syntax()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->syntax().data(), this->syntax().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FileDescriptorProto.syntax"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 12, this->syntax(), target); + } + + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -1490,7 +1614,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( int FileDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 3) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -1506,7 +1630,7 @@ int FileDescriptorProto::ByteSize() const { } } - if (_has_bits_[9 / 32] & (0xffu << (9 % 32))) { + if (_has_bits_[9 / 32] & 3584) { // optional .google.protobuf.FileOptions options = 8; if (has_options()) { total_size += 1 + @@ -1521,6 +1645,13 @@ int FileDescriptorProto::ByteSize() const { this->source_code_info()); } + // optional string syntax = 12; + if (has_syntax()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->syntax()); + } + } // repeated string dependency = 3; total_size += 1 * this->dependency_size(); @@ -1581,7 +1712,7 @@ int FileDescriptorProto::ByteSize() const { this->extension(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -1628,8 +1759,13 @@ void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { if (from.has_source_code_info()) { mutable_source_code_info()->::google::protobuf::SourceCodeInfo::MergeFrom(from.source_code_info()); } + if (from.has_syntax()) { + set_syntax(from.syntax()); + } + } + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); } void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -1657,22 +1793,37 @@ bool FileDescriptorProto::IsInitialized() const { } void FileDescriptorProto::Swap(FileDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(package_, other->package_); - dependency_.Swap(&other->dependency_); - public_dependency_.Swap(&other->public_dependency_); - weak_dependency_.Swap(&other->weak_dependency_); - message_type_.Swap(&other->message_type_); - enum_type_.Swap(&other->enum_type_); - service_.Swap(&other->service_); - extension_.Swap(&other->extension_); - std::swap(options_, other->options_); - std::swap(source_code_info_, other->source_code_info_); - 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 { + FileDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void FileDescriptorProto::UnsafeArenaSwap(FileDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) { + name_.Swap(&other->name_); + package_.Swap(&other->package_); + dependency_.UnsafeArenaSwap(&other->dependency_); + public_dependency_.UnsafeArenaSwap(&other->public_dependency_); + weak_dependency_.UnsafeArenaSwap(&other->weak_dependency_); + message_type_.UnsafeArenaSwap(&other->message_type_); + enum_type_.UnsafeArenaSwap(&other->enum_type_); + service_.UnsafeArenaSwap(&other->service_); + extension_.UnsafeArenaSwap(&other->extension_); + std::swap(options_, other->options_); + std::swap(source_code_info_, other->source_code_info_); + syntax_.Swap(&other->syntax_); + 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 FileDescriptorProto::GetMetadata() const { @@ -1692,16 +1843,25 @@ const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ExtensionRange) } +DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ExtensionRange) +} + void DescriptorProto_ExtensionRange::InitAsDefaultInstance() { } DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ExtensionRange) @@ -1720,10 +1880,20 @@ DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() { } void DescriptorProto_ExtensionRange::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void DescriptorProto_ExtensionRange::ArenaDtor(void* object) { + DescriptorProto_ExtensionRange* _this = reinterpret_cast< DescriptorProto_ExtensionRange* >(object); + (void)_this; +} +void DescriptorProto_ExtensionRange::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void DescriptorProto_ExtensionRange::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -1741,8 +1911,8 @@ const DescriptorProto_ExtensionRange& DescriptorProto_ExtensionRange::default_in DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::default_instance_ = NULL; -DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New() const { - return new DescriptorProto_ExtensionRange; +DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void DescriptorProto_ExtensionRange::Clear() { @@ -1762,7 +1932,9 @@ void DescriptorProto_ExtensionRange::Clear() { #undef ZR_ ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( @@ -1839,7 +2011,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -1859,7 +2031,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -1870,7 +2042,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( int DescriptorProto_ExtensionRange::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 3) { // optional int32 start = 1; if (has_start()) { total_size += 1 + @@ -1886,7 +2058,7 @@ int DescriptorProto_ExtensionRange::ByteSize() const { } } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -1919,7 +2091,9 @@ void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRa set_end(from.end()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) { @@ -1940,14 +2114,28 @@ bool DescriptorProto_ExtensionRange::IsInitialized() const { } void DescriptorProto_ExtensionRange::Swap(DescriptorProto_ExtensionRange* other) { - if (other != this) { - std::swap(start_, other->start_); - std::swap(end_, other->end_); - 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 { + DescriptorProto_ExtensionRange temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void DescriptorProto_ExtensionRange::UnsafeArenaSwap(DescriptorProto_ExtensionRange* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange* other) { + std::swap(start_, other->start_); + std::swap(end_, other->end_); + 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 DescriptorProto_ExtensionRange::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -1972,17 +2160,32 @@ const int DescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER DescriptorProto::DescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto) } +DescriptorProto::DescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + field_(arena), + extension_(arena), + nested_type_(arena), + enum_type_(arena), + extension_range_(arena), + oneof_decl_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto) +} + void DescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MessageOptions*>(&::google::protobuf::MessageOptions::default_instance()); } DescriptorProto::DescriptorProto(const DescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto) @@ -1991,7 +2194,7 @@ DescriptorProto::DescriptorProto(const DescriptorProto& from) void DescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -2002,14 +2205,22 @@ DescriptorProto::~DescriptorProto() { } void DescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void DescriptorProto::ArenaDtor(void* object) { + DescriptorProto* _this = reinterpret_cast< DescriptorProto* >(object); + (void)_this; +} +void DescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void DescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -2027,16 +2238,14 @@ const DescriptorProto& DescriptorProto::default_instance() { DescriptorProto* DescriptorProto::default_instance_ = NULL; -DescriptorProto* DescriptorProto::New() const { - return new DescriptorProto; +DescriptorProto* DescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void DescriptorProto::Clear() { if (_has_bits_[0 / 32] & 129) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_options()) { if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); @@ -2049,7 +2258,9 @@ void DescriptorProto::Clear() { extension_range_.Clear(); oneof_decl_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool DescriptorProto::MergePartialFromCodedStream( @@ -2070,7 +2281,7 @@ bool DescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.DescriptorProto.name"); } else { goto handle_unusual; } @@ -2205,7 +2416,7 @@ void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.DescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -2252,7 +2463,7 @@ void DescriptorProto::SerializeWithCachedSizes( 8, this->oneof_decl(i), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -2267,7 +2478,7 @@ void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.DescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -2322,7 +2533,7 @@ void DescriptorProto::SerializeWithCachedSizes( 8, this->oneof_decl(i), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -2333,7 +2544,7 @@ void DescriptorProto::SerializeWithCachedSizes( int DescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 129) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -2397,7 +2608,7 @@ int DescriptorProto::ByteSize() const { this->oneof_decl(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -2436,7 +2647,9 @@ void DescriptorProto::MergeFrom(const DescriptorProto& from) { mutable_options()->::google::protobuf::MessageOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -2464,19 +2677,33 @@ bool DescriptorProto::IsInitialized() const { } void DescriptorProto::Swap(DescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - field_.Swap(&other->field_); - extension_.Swap(&other->extension_); - nested_type_.Swap(&other->nested_type_); - enum_type_.Swap(&other->enum_type_); - extension_range_.Swap(&other->extension_range_); - oneof_decl_.Swap(&other->oneof_decl_); - std::swap(options_, other->options_); - 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 { + DescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void DescriptorProto::UnsafeArenaSwap(DescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void DescriptorProto::InternalSwap(DescriptorProto* other) { + name_.Swap(&other->name_); + field_.UnsafeArenaSwap(&other->field_); + extension_.UnsafeArenaSwap(&other->extension_); + nested_type_.UnsafeArenaSwap(&other->nested_type_); + enum_type_.UnsafeArenaSwap(&other->enum_type_); + extension_range_.UnsafeArenaSwap(&other->extension_range_); + oneof_decl_.UnsafeArenaSwap(&other->oneof_decl_); + std::swap(options_, other->options_); + 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 DescriptorProto::GetMetadata() const { @@ -2579,17 +2806,26 @@ const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FieldDescriptorProto::FieldDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FieldDescriptorProto) } +FieldDescriptorProto::FieldDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldDescriptorProto) +} + void FieldDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FieldOptions*>(&::google::protobuf::FieldOptions::default_instance()); } FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldDescriptorProto) @@ -2598,13 +2834,13 @@ FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) void FieldDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); number_ = 0; label_ = 1; type_ = 1; - type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + type_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); oneof_index_ = 0; options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -2616,23 +2852,25 @@ FieldDescriptorProto::~FieldDescriptorProto() { } void FieldDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; - } - if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete type_name_; - } - if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete extendee_; - } - if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete default_value_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + type_name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + extendee_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + default_value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void FieldDescriptorProto::ArenaDtor(void* object) { + FieldDescriptorProto* _this = reinterpret_cast< FieldDescriptorProto* >(object); + (void)_this; +} +void FieldDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FieldDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -2650,34 +2888,26 @@ const FieldDescriptorProto& FieldDescriptorProto::default_instance() { FieldDescriptorProto* FieldDescriptorProto::default_instance_ = NULL; -FieldDescriptorProto* FieldDescriptorProto::New() const { - return new FieldDescriptorProto; +FieldDescriptorProto* FieldDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void FieldDescriptorProto::Clear() { if (_has_bits_[0 / 32] & 255) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } number_ = 0; label_ = 1; type_ = 1; if (has_type_name()) { - if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_->clear(); - } + type_name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_extendee()) { - if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_->clear(); - } + extendee_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_default_value()) { - if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_->clear(); - } + default_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } oneof_index_ = 0; } @@ -2685,7 +2915,9 @@ void FieldDescriptorProto::Clear() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); } ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool FieldDescriptorProto::MergePartialFromCodedStream( @@ -2706,7 +2938,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.FieldDescriptorProto.name"); } else { goto handle_unusual; } @@ -2723,7 +2955,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->extendee().data(), this->extendee().length(), ::google::protobuf::internal::WireFormat::PARSE, - "extendee"); + "google.protobuf.FieldDescriptorProto.extendee"); } else { goto handle_unusual; } @@ -2795,7 +3027,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->type_name().data(), this->type_name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "type_name"); + "google.protobuf.FieldDescriptorProto.type_name"); } else { goto handle_unusual; } @@ -2812,7 +3044,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->default_value().data(), this->default_value().length(), ::google::protobuf::internal::WireFormat::PARSE, - "default_value"); + "google.protobuf.FieldDescriptorProto.default_value"); } else { goto handle_unusual; } @@ -2878,7 +3110,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.FieldDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -2888,7 +3120,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->extendee().data(), this->extendee().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "extendee"); + "google.protobuf.FieldDescriptorProto.extendee"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->extendee(), output); } @@ -2915,7 +3147,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->type_name().data(), this->type_name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "type_name"); + "google.protobuf.FieldDescriptorProto.type_name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 6, this->type_name(), output); } @@ -2925,7 +3157,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->default_value().data(), this->default_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "default_value"); + "google.protobuf.FieldDescriptorProto.default_value"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 7, this->default_value(), output); } @@ -2941,7 +3173,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -2956,7 +3188,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.FieldDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -2967,7 +3199,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->extendee().data(), this->extendee().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "extendee"); + "google.protobuf.FieldDescriptorProto.extendee"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 2, this->extendee(), target); @@ -2995,7 +3227,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->type_name().data(), this->type_name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "type_name"); + "google.protobuf.FieldDescriptorProto.type_name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 6, this->type_name(), target); @@ -3006,7 +3238,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->default_value().data(), this->default_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "default_value"); + "google.protobuf.FieldDescriptorProto.default_value"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 7, this->default_value(), target); @@ -3024,7 +3256,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -3035,7 +3267,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( int FieldDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 255) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -3091,16 +3323,14 @@ int FieldDescriptorProto::ByteSize() const { } } - if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { - // optional .google.protobuf.FieldOptions options = 8; - if (has_options()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->options()); - } - + // optional .google.protobuf.FieldOptions options = 8; + if (has_options()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->options()); } - if (!unknown_fields().empty()) { + + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -3156,7 +3386,9 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -3180,20 +3412,34 @@ bool FieldDescriptorProto::IsInitialized() const { } void FieldDescriptorProto::Swap(FieldDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(number_, other->number_); - std::swap(label_, other->label_); - std::swap(type_, other->type_); - std::swap(type_name_, other->type_name_); - std::swap(extendee_, other->extendee_); - std::swap(default_value_, other->default_value_); - std::swap(oneof_index_, other->oneof_index_); - std::swap(options_, other->options_); - 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 { + FieldDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void FieldDescriptorProto::UnsafeArenaSwap(FieldDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { + name_.Swap(&other->name_); + std::swap(number_, other->number_); + std::swap(label_, other->label_); + std::swap(type_, other->type_); + type_name_.Swap(&other->type_name_); + extendee_.Swap(&other->extendee_); + default_value_.Swap(&other->default_value_); + std::swap(oneof_index_, other->oneof_index_); + std::swap(options_, other->options_); + 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 FieldDescriptorProto::GetMetadata() const { @@ -3212,16 +3458,25 @@ const int OneofDescriptorProto::kNameFieldNumber; #endif // !_MSC_VER OneofDescriptorProto::OneofDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto) } +OneofDescriptorProto::OneofDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofDescriptorProto) +} + void OneofDescriptorProto::InitAsDefaultInstance() { } OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofDescriptorProto) @@ -3230,7 +3485,7 @@ OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from) void OneofDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -3240,13 +3495,21 @@ OneofDescriptorProto::~OneofDescriptorProto() { } void OneofDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void OneofDescriptorProto::ArenaDtor(void* object) { + OneofDescriptorProto* _this = reinterpret_cast< OneofDescriptorProto* >(object); + (void)_this; +} +void OneofDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void OneofDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -3264,18 +3527,18 @@ const OneofDescriptorProto& OneofDescriptorProto::default_instance() { OneofDescriptorProto* OneofDescriptorProto::default_instance_ = NULL; -OneofDescriptorProto* OneofDescriptorProto::New() const { - return new OneofDescriptorProto; +OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void OneofDescriptorProto::Clear() { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.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 OneofDescriptorProto::MergePartialFromCodedStream( @@ -3296,7 +3559,7 @@ bool OneofDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.OneofDescriptorProto.name"); } else { goto handle_unusual; } @@ -3334,12 +3597,12 @@ void OneofDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.OneofDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -3354,13 +3617,13 @@ void OneofDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.OneofDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -3371,16 +3634,14 @@ void OneofDescriptorProto::SerializeWithCachedSizes( int OneofDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional string name = 1; - if (has_name()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->name()); - } - + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); } - if (!unknown_fields().empty()) { + + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -3410,7 +3671,9 @@ void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) { set_name(from.name()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void OneofDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -3431,13 +3694,27 @@ bool OneofDescriptorProto::IsInitialized() const { } void OneofDescriptorProto::Swap(OneofDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - 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 { + OneofDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void OneofDescriptorProto::UnsafeArenaSwap(OneofDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) { + name_.Swap(&other->name_); + 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 OneofDescriptorProto::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -3457,17 +3734,27 @@ const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumDescriptorProto::EnumDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumDescriptorProto) } +EnumDescriptorProto::EnumDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + value_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto) +} + void EnumDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumOptions*>(&::google::protobuf::EnumOptions::default_instance()); } EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto) @@ -3476,7 +3763,7 @@ EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) void EnumDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -3487,14 +3774,22 @@ EnumDescriptorProto::~EnumDescriptorProto() { } void EnumDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void EnumDescriptorProto::ArenaDtor(void* object) { + EnumDescriptorProto* _this = reinterpret_cast< EnumDescriptorProto* >(object); + (void)_this; +} +void EnumDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void EnumDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -3512,16 +3807,14 @@ const EnumDescriptorProto& EnumDescriptorProto::default_instance() { EnumDescriptorProto* EnumDescriptorProto::default_instance_ = NULL; -EnumDescriptorProto* EnumDescriptorProto::New() const { - return new EnumDescriptorProto; +EnumDescriptorProto* EnumDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void EnumDescriptorProto::Clear() { if (_has_bits_[0 / 32] & 5) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_options()) { if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); @@ -3529,7 +3822,9 @@ void EnumDescriptorProto::Clear() { } value_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool EnumDescriptorProto::MergePartialFromCodedStream( @@ -3550,7 +3845,7 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.EnumDescriptorProto.name"); } else { goto handle_unusual; } @@ -3615,7 +3910,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.EnumDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -3632,7 +3927,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( 3, this->options(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -3647,7 +3942,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.EnumDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -3667,7 +3962,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( 3, this->options(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -3678,7 +3973,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( int EnumDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 5) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -3702,7 +3997,7 @@ int EnumDescriptorProto::ByteSize() const { this->value(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -3736,7 +4031,9 @@ void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { mutable_options()->::google::protobuf::EnumOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -3761,15 +4058,29 @@ bool EnumDescriptorProto::IsInitialized() const { } void EnumDescriptorProto::Swap(EnumDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - value_.Swap(&other->value_); - std::swap(options_, other->options_); - 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 { + EnumDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void EnumDescriptorProto::UnsafeArenaSwap(EnumDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) { + name_.Swap(&other->name_); + value_.UnsafeArenaSwap(&other->value_); + std::swap(options_, other->options_); + 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 EnumDescriptorProto::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -3789,17 +4100,26 @@ const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumValueDescriptorProto::EnumValueDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumValueDescriptorProto) } +EnumValueDescriptorProto::EnumValueDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueDescriptorProto) +} + void EnumValueDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumValueOptions*>(&::google::protobuf::EnumValueOptions::default_instance()); } EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueDescriptorProto) @@ -3808,7 +4128,7 @@ EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProt void EnumValueDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); number_ = 0; options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -3820,14 +4140,22 @@ EnumValueDescriptorProto::~EnumValueDescriptorProto() { } void EnumValueDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void EnumValueDescriptorProto::ArenaDtor(void* object) { + EnumValueDescriptorProto* _this = reinterpret_cast< EnumValueDescriptorProto* >(object); + (void)_this; +} +void EnumValueDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void EnumValueDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -3845,16 +4173,14 @@ const EnumValueDescriptorProto& EnumValueDescriptorProto::default_instance() { EnumValueDescriptorProto* EnumValueDescriptorProto::default_instance_ = NULL; -EnumValueDescriptorProto* EnumValueDescriptorProto::New() const { - return new EnumValueDescriptorProto; +EnumValueDescriptorProto* EnumValueDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void EnumValueDescriptorProto::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()); } number_ = 0; if (has_options()) { @@ -3862,7 +4188,9 @@ void EnumValueDescriptorProto::Clear() { } } ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool EnumValueDescriptorProto::MergePartialFromCodedStream( @@ -3883,7 +4211,7 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.EnumValueDescriptorProto.name"); } else { goto handle_unusual; } @@ -3949,7 +4277,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.EnumValueDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -3965,7 +4293,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( 3, this->options(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -3980,7 +4308,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.EnumValueDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -3998,7 +4326,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( 3, this->options(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -4009,7 +4337,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( int EnumValueDescriptorProto::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 + @@ -4032,7 +4360,7 @@ int EnumValueDescriptorProto::ByteSize() const { } } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -4068,7 +4396,9 @@ void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { mutable_options()->::google::protobuf::EnumValueOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -4092,15 +4422,29 @@ bool EnumValueDescriptorProto::IsInitialized() const { } void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(number_, other->number_); - std::swap(options_, other->options_); - 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 { + EnumValueDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void EnumValueDescriptorProto::UnsafeArenaSwap(EnumValueDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) { + name_.Swap(&other->name_); + std::swap(number_, other->number_); + std::swap(options_, other->options_); + 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 EnumValueDescriptorProto::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -4120,17 +4464,27 @@ const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER ServiceDescriptorProto::ServiceDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.ServiceDescriptorProto) } +ServiceDescriptorProto::ServiceDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + method_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceDescriptorProto) +} + void ServiceDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::ServiceOptions*>(&::google::protobuf::ServiceOptions::default_instance()); } ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceDescriptorProto) @@ -4139,7 +4493,7 @@ ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& fro void ServiceDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4150,14 +4504,22 @@ ServiceDescriptorProto::~ServiceDescriptorProto() { } void ServiceDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void ServiceDescriptorProto::ArenaDtor(void* object) { + ServiceDescriptorProto* _this = reinterpret_cast< ServiceDescriptorProto* >(object); + (void)_this; +} +void ServiceDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void ServiceDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -4175,16 +4537,14 @@ const ServiceDescriptorProto& ServiceDescriptorProto::default_instance() { ServiceDescriptorProto* ServiceDescriptorProto::default_instance_ = NULL; -ServiceDescriptorProto* ServiceDescriptorProto::New() const { - return new ServiceDescriptorProto; +ServiceDescriptorProto* ServiceDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void ServiceDescriptorProto::Clear() { if (_has_bits_[0 / 32] & 5) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_options()) { if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); @@ -4192,7 +4552,9 @@ void ServiceDescriptorProto::Clear() { } method_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool ServiceDescriptorProto::MergePartialFromCodedStream( @@ -4213,7 +4575,7 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.ServiceDescriptorProto.name"); } else { goto handle_unusual; } @@ -4278,7 +4640,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.ServiceDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -4295,7 +4657,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( 3, this->options(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -4310,7 +4672,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.ServiceDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -4330,7 +4692,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( 3, this->options(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -4341,7 +4703,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( int ServiceDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 5) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -4365,7 +4727,7 @@ int ServiceDescriptorProto::ByteSize() const { this->method(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -4399,7 +4761,9 @@ void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { mutable_options()->::google::protobuf::ServiceOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -4424,15 +4788,29 @@ bool ServiceDescriptorProto::IsInitialized() const { } void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - method_.Swap(&other->method_); - std::swap(options_, other->options_); - 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 { + ServiceDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void ServiceDescriptorProto::UnsafeArenaSwap(ServiceDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) { + name_.Swap(&other->name_); + method_.UnsafeArenaSwap(&other->method_); + std::swap(options_, other->options_); + 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 ServiceDescriptorProto::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -4453,17 +4831,26 @@ const int MethodDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto) } +MethodDescriptorProto::MethodDescriptorProto(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodDescriptorProto) +} + void MethodDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MethodOptions*>(&::google::protobuf::MethodOptions::default_instance()); } MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodDescriptorProto) @@ -4472,9 +4859,9 @@ MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) void MethodDescriptorProto::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + input_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + output_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4485,20 +4872,24 @@ MethodDescriptorProto::~MethodDescriptorProto() { } void MethodDescriptorProto::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; - } - if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete input_type_; - } - if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete output_type_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + input_type_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + output_type_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { delete options_; } } +void MethodDescriptorProto::ArenaDtor(void* object) { + MethodDescriptorProto* _this = reinterpret_cast< MethodDescriptorProto* >(object); + (void)_this; +} +void MethodDescriptorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void MethodDescriptorProto::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -4516,33 +4907,29 @@ const MethodDescriptorProto& MethodDescriptorProto::default_instance() { MethodDescriptorProto* MethodDescriptorProto::default_instance_ = NULL; -MethodDescriptorProto* MethodDescriptorProto::New() const { - return new MethodDescriptorProto; +MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void MethodDescriptorProto::Clear() { if (_has_bits_[0 / 32] & 15) { if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_input_type()) { - if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_->clear(); - } + input_type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_output_type()) { - if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_->clear(); - } + output_type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_options()) { if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); } } ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool MethodDescriptorProto::MergePartialFromCodedStream( @@ -4563,7 +4950,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name"); + "google.protobuf.MethodDescriptorProto.name"); } else { goto handle_unusual; } @@ -4580,7 +4967,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->input_type().data(), this->input_type().length(), ::google::protobuf::internal::WireFormat::PARSE, - "input_type"); + "google.protobuf.MethodDescriptorProto.input_type"); } else { goto handle_unusual; } @@ -4597,7 +4984,7 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->output_type().data(), this->output_type().length(), ::google::protobuf::internal::WireFormat::PARSE, - "output_type"); + "google.protobuf.MethodDescriptorProto.output_type"); } else { goto handle_unusual; } @@ -4648,7 +5035,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.MethodDescriptorProto.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); } @@ -4658,7 +5045,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->input_type().data(), this->input_type().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "input_type"); + "google.protobuf.MethodDescriptorProto.input_type"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->input_type(), output); } @@ -4668,7 +5055,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->output_type().data(), this->output_type().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "output_type"); + "google.protobuf.MethodDescriptorProto.output_type"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 3, this->output_type(), output); } @@ -4679,7 +5066,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( 4, this->options(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -4694,7 +5081,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name().data(), this->name().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name"); + "google.protobuf.MethodDescriptorProto.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name(), target); @@ -4705,7 +5092,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->input_type().data(), this->input_type().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "input_type"); + "google.protobuf.MethodDescriptorProto.input_type"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 2, this->input_type(), target); @@ -4716,7 +5103,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->output_type().data(), this->output_type().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "output_type"); + "google.protobuf.MethodDescriptorProto.output_type"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 3, this->output_type(), target); @@ -4729,7 +5116,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( 4, this->options(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -4740,7 +5127,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( int MethodDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 15) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -4770,7 +5157,7 @@ int MethodDescriptorProto::ByteSize() const { } } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -4809,7 +5196,9 @@ void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { @@ -4833,16 +5222,30 @@ bool MethodDescriptorProto::IsInitialized() const { } void MethodDescriptorProto::Swap(MethodDescriptorProto* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(input_type_, other->input_type_); - std::swap(output_type_, other->output_type_); - std::swap(options_, other->options_); - 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 { + MethodDescriptorProto temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void MethodDescriptorProto::UnsafeArenaSwap(MethodDescriptorProto* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { + name_.Swap(&other->name_); + input_type_.Swap(&other->input_type_); + output_type_.Swap(&other->output_type_); + std::swap(options_, other->options_); + 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 MethodDescriptorProto::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -4894,16 +5297,26 @@ const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FileOptions::FileOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileOptions) } +FileOptions::FileOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FileOptions) +} + void FileOptions::InitAsDefaultInstance() { } FileOptions::FileOptions(const FileOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.FileOptions) @@ -4912,13 +5325,13 @@ FileOptions::FileOptions(const FileOptions& from) void FileOptions::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + java_package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + java_outer_classname_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); java_multiple_files_ = false; java_generate_equals_and_hash_ = false; java_string_check_utf8_ = false; optimize_for_ = 1; - go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + go_package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); cc_generic_services_ = false; java_generic_services_ = false; py_generic_services_ = false; @@ -4932,19 +5345,23 @@ FileOptions::~FileOptions() { } void FileOptions::SharedDtor() { - if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete java_package_; - } - if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete java_outer_classname_; - } - if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete go_package_; + if (GetArenaNoVirtual() != NULL) { + return; } + + java_package_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + java_outer_classname_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + go_package_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void FileOptions::ArenaDtor(void* object) { + FileOptions* _this = reinterpret_cast< FileOptions* >(object); + (void)_this; +} +void FileOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FileOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -4962,8 +5379,8 @@ const FileOptions& FileOptions::default_instance() { FileOptions* FileOptions::default_instance_ = NULL; -FileOptions* FileOptions::New() const { - return new FileOptions; +FileOptions* FileOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void FileOptions::Clear() { @@ -4981,20 +5398,14 @@ void FileOptions::Clear() { if (_has_bits_[0 / 32] & 255) { ZR_(java_multiple_files_, cc_generic_services_); if (has_java_package()) { - if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_->clear(); - } + java_package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_java_outer_classname()) { - if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_->clear(); - } + java_outer_classname_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } optimize_for_ = 1; if (has_go_package()) { - if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_->clear(); - } + go_package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } } ZR_(java_generic_services_, deprecated_); @@ -5004,7 +5415,9 @@ void FileOptions::Clear() { uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool FileOptions::MergePartialFromCodedStream( @@ -5025,7 +5438,7 @@ bool FileOptions::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_package().data(), this->java_package().length(), ::google::protobuf::internal::WireFormat::PARSE, - "java_package"); + "google.protobuf.FileOptions.java_package"); } else { goto handle_unusual; } @@ -5042,7 +5455,7 @@ bool FileOptions::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_outer_classname().data(), this->java_outer_classname().length(), ::google::protobuf::internal::WireFormat::PARSE, - "java_outer_classname"); + "google.protobuf.FileOptions.java_outer_classname"); } else { goto handle_unusual; } @@ -5094,7 +5507,7 @@ bool FileOptions::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->go_package().data(), this->go_package().length(), ::google::protobuf::internal::WireFormat::PARSE, - "go_package"); + "google.protobuf.FileOptions.go_package"); } else { goto handle_unusual; } @@ -5241,7 +5654,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_package().data(), this->java_package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "java_package"); + "google.protobuf.FileOptions.java_package"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->java_package(), output); } @@ -5251,7 +5664,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_outer_classname().data(), this->java_outer_classname().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "java_outer_classname"); + "google.protobuf.FileOptions.java_outer_classname"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 8, this->java_outer_classname(), output); } @@ -5272,7 +5685,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->go_package().data(), this->go_package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "go_package"); + "google.protobuf.FileOptions.go_package"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 11, this->go_package(), output); } @@ -5317,7 +5730,7 @@ void FileOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -5332,7 +5745,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_package().data(), this->java_package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "java_package"); + "google.protobuf.FileOptions.java_package"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->java_package(), target); @@ -5343,7 +5756,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->java_outer_classname().data(), this->java_outer_classname().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "java_outer_classname"); + "google.protobuf.FileOptions.java_outer_classname"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 8, this->java_outer_classname(), target); @@ -5365,7 +5778,7 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->go_package().data(), this->go_package().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "go_package"); + "google.protobuf.FileOptions.go_package"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 11, this->go_package(), target); @@ -5412,7 +5825,7 @@ void FileOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -5423,7 +5836,7 @@ void FileOptions::SerializeWithCachedSizes( int FileOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 255) { // optional string java_package = 1; if (has_java_package()) { total_size += 1 + @@ -5472,7 +5885,7 @@ int FileOptions::ByteSize() const { } } - if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + if (_has_bits_[8 / 32] & 1792) { // optional bool java_generic_services = 17 [default = false]; if (has_java_generic_services()) { total_size += 2 + 1; @@ -5499,7 +5912,7 @@ int FileOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -5563,7 +5976,9 @@ void FileOptions::MergeFrom(const FileOptions& from) { } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void FileOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -5586,24 +6001,38 @@ bool FileOptions::IsInitialized() const { } void FileOptions::Swap(FileOptions* other) { - if (other != this) { - std::swap(java_package_, other->java_package_); - std::swap(java_outer_classname_, other->java_outer_classname_); - std::swap(java_multiple_files_, other->java_multiple_files_); - std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_); - std::swap(java_string_check_utf8_, other->java_string_check_utf8_); - std::swap(optimize_for_, other->optimize_for_); - std::swap(go_package_, other->go_package_); - std::swap(cc_generic_services_, other->cc_generic_services_); - std::swap(java_generic_services_, other->java_generic_services_); - std::swap(py_generic_services_, other->py_generic_services_); - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); - } + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + FileOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void FileOptions::UnsafeArenaSwap(FileOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void FileOptions::InternalSwap(FileOptions* other) { + java_package_.Swap(&other->java_package_); + java_outer_classname_.Swap(&other->java_outer_classname_); + std::swap(java_multiple_files_, other->java_multiple_files_); + std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_); + std::swap(java_string_check_utf8_, other->java_string_check_utf8_); + std::swap(optimize_for_, other->optimize_for_); + go_package_.Swap(&other->go_package_); + std::swap(cc_generic_services_, other->cc_generic_services_); + std::swap(java_generic_services_, other->java_generic_services_); + std::swap(py_generic_services_, other->py_generic_services_); + std::swap(deprecated_, other->deprecated_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); } ::google::protobuf::Metadata FileOptions::GetMetadata() const { @@ -5621,20 +6050,31 @@ void FileOptions::Swap(FileOptions* other) { const int MessageOptions::kMessageSetWireFormatFieldNumber; const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber; const int MessageOptions::kDeprecatedFieldNumber; +const int MessageOptions::kMapEntryFieldNumber; const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MessageOptions::MessageOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MessageOptions) } +MessageOptions::MessageOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.MessageOptions) +} + void MessageOptions::InitAsDefaultInstance() { } MessageOptions::MessageOptions(const MessageOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.MessageOptions) @@ -5645,6 +6085,7 @@ void MessageOptions::SharedCtor() { message_set_wire_format_ = false; no_standard_descriptor_accessor_ = false; deprecated_ = false; + map_entry_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -5654,10 +6095,20 @@ MessageOptions::~MessageOptions() { } void MessageOptions::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void MessageOptions::ArenaDtor(void* object) { + MessageOptions* _this = reinterpret_cast< MessageOptions* >(object); + (void)_this; +} +void MessageOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void MessageOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -5675,8 +6126,8 @@ const MessageOptions& MessageOptions::default_instance() { MessageOptions* MessageOptions::default_instance_ = NULL; -MessageOptions* MessageOptions::New() const { - return new MessageOptions; +MessageOptions* MessageOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void MessageOptions::Clear() { @@ -5691,14 +6142,16 @@ void MessageOptions::Clear() { ::memset(&first, 0, n); \ } while (0) - ZR_(message_set_wire_format_, deprecated_); + ZR_(message_set_wire_format_, map_entry_); #undef OFFSET_OF_FIELD_ #undef ZR_ uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool MessageOptions::MergePartialFromCodedStream( @@ -5751,6 +6204,21 @@ bool MessageOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(56)) goto parse_map_entry; + break; + } + + // optional bool map_entry = 7; + case 7: { + if (tag == 56) { + parse_map_entry: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &map_entry_))); + set_has_map_entry(); + } else { + goto handle_unusual; + } if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } @@ -5814,6 +6282,11 @@ void MessageOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output); } + // optional bool map_entry = 7; + if (has_map_entry()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->map_entry(), output); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( @@ -5824,7 +6297,7 @@ void MessageOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -5849,6 +6322,11 @@ void MessageOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target); } + // optional bool map_entry = 7; + if (has_map_entry()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->map_entry(), target); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -5860,7 +6338,7 @@ void MessageOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -5871,7 +6349,7 @@ void MessageOptions::SerializeWithCachedSizes( int MessageOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 15) { // optional bool message_set_wire_format = 1 [default = false]; if (has_message_set_wire_format()) { total_size += 1 + 1; @@ -5887,6 +6365,11 @@ int MessageOptions::ByteSize() const { total_size += 1 + 1; } + // optional bool map_entry = 7; + if (has_map_entry()) { + total_size += 1 + 1; + } + } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -5898,7 +6381,7 @@ int MessageOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -5934,9 +6417,14 @@ void MessageOptions::MergeFrom(const MessageOptions& from) { if (from.has_deprecated()) { set_deprecated(from.deprecated()); } + if (from.has_map_entry()) { + set_map_entry(from.map_entry()); + } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -5959,17 +6447,32 @@ bool MessageOptions::IsInitialized() const { } void MessageOptions::Swap(MessageOptions* other) { - if (other != this) { - std::swap(message_set_wire_format_, other->message_set_wire_format_); - std::swap(no_standard_descriptor_accessor_, other->no_standard_descriptor_accessor_); - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + MessageOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void MessageOptions::UnsafeArenaSwap(MessageOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void MessageOptions::InternalSwap(MessageOptions* other) { + std::swap(message_set_wire_format_, other->message_set_wire_format_); + std::swap(no_standard_descriptor_accessor_, other->no_standard_descriptor_accessor_); + std::swap(deprecated_, other->deprecated_); + std::swap(map_entry_, other->map_entry_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); +} ::google::protobuf::Metadata MessageOptions::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -6010,35 +6513,42 @@ const int FieldOptions::kCtypeFieldNumber; const int FieldOptions::kPackedFieldNumber; const int FieldOptions::kLazyFieldNumber; const int FieldOptions::kDeprecatedFieldNumber; -const int FieldOptions::kExperimentalMapKeyFieldNumber; const int FieldOptions::kWeakFieldNumber; const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FieldOptions::FieldOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FieldOptions) } +FieldOptions::FieldOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldOptions) +} + void FieldOptions::InitAsDefaultInstance() { } FieldOptions::FieldOptions(const FieldOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldOptions) } void FieldOptions::SharedCtor() { - ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; ctype_ = 0; packed_ = false; lazy_ = false; deprecated_ = false; - experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); weak_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -6049,13 +6559,20 @@ FieldOptions::~FieldOptions() { } void FieldOptions::SharedDtor() { - if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete experimental_map_key_; + if (GetArenaNoVirtual() != NULL) { + return; } + if (this != default_instance_) { } } +void FieldOptions::ArenaDtor(void* object) { + FieldOptions* _this = reinterpret_cast< FieldOptions* >(object); + (void)_this; +} +void FieldOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void FieldOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -6073,8 +6590,8 @@ const FieldOptions& FieldOptions::default_instance() { FieldOptions* FieldOptions::default_instance_ = NULL; -FieldOptions* FieldOptions::New() const { - return new FieldOptions; +FieldOptions* FieldOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void FieldOptions::Clear() { @@ -6089,13 +6606,8 @@ void FieldOptions::Clear() { ::memset(&first, 0, n); \ } while (0) - if (_has_bits_[0 / 32] & 63) { + if (_has_bits_[0 / 32] & 31) { ZR_(ctype_, weak_); - if (has_experimental_map_key()) { - if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_->clear(); - } - } } #undef OFFSET_OF_FIELD_ @@ -6103,7 +6615,9 @@ void FieldOptions::Clear() { uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool FieldOptions::MergePartialFromCodedStream( @@ -6176,23 +6690,6 @@ bool FieldOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(74)) goto parse_experimental_map_key; - break; - } - - // optional string experimental_map_key = 9; - case 9: { - if (tag == 74) { - parse_experimental_map_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_experimental_map_key())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "experimental_map_key"); - } else { - goto handle_unusual; - } if (input->ExpectTag(80)) goto parse_weak; break; } @@ -6277,16 +6774,6 @@ void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output); } - // optional string experimental_map_key = 9; - if (has_experimental_map_key()) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "experimental_map_key"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 9, this->experimental_map_key(), output); - } - // optional bool weak = 10 [default = false]; if (has_weak()) { ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output); @@ -6302,7 +6789,7 @@ void FieldOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -6333,17 +6820,6 @@ void FieldOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target); } - // optional string experimental_map_key = 9; - if (has_experimental_map_key()) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "experimental_map_key"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 9, this->experimental_map_key(), target); - } - // optional bool weak = 10 [default = false]; if (has_weak()) { target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target); @@ -6360,7 +6836,7 @@ void FieldOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -6371,7 +6847,7 @@ void FieldOptions::SerializeWithCachedSizes( int FieldOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 31) { // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (has_ctype()) { total_size += 1 + @@ -6393,13 +6869,6 @@ int FieldOptions::ByteSize() const { total_size += 1 + 1; } - // optional string experimental_map_key = 9; - if (has_experimental_map_key()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->experimental_map_key()); - } - // optional bool weak = 10 [default = false]; if (has_weak()) { total_size += 1 + 1; @@ -6416,7 +6885,7 @@ int FieldOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -6455,15 +6924,14 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { if (from.has_deprecated()) { set_deprecated(from.deprecated()); } - if (from.has_experimental_map_key()) { - set_experimental_map_key(from.experimental_map_key()); - } if (from.has_weak()) { set_weak(from.weak()); } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -6486,19 +6954,32 @@ bool FieldOptions::IsInitialized() const { } void FieldOptions::Swap(FieldOptions* other) { - if (other != this) { - std::swap(ctype_, other->ctype_); - std::swap(packed_, other->packed_); - std::swap(lazy_, other->lazy_); - std::swap(deprecated_, other->deprecated_); - std::swap(experimental_map_key_, other->experimental_map_key_); - std::swap(weak_, other->weak_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); - } + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + FieldOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void FieldOptions::UnsafeArenaSwap(FieldOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void FieldOptions::InternalSwap(FieldOptions* other) { + std::swap(ctype_, other->ctype_); + std::swap(packed_, other->packed_); + std::swap(lazy_, other->lazy_); + std::swap(deprecated_, other->deprecated_); + std::swap(weak_, other->weak_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); } ::google::protobuf::Metadata FieldOptions::GetMetadata() const { @@ -6519,16 +7000,26 @@ const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumOptions::EnumOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumOptions) } +EnumOptions::EnumOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumOptions) +} + void EnumOptions::InitAsDefaultInstance() { } EnumOptions::EnumOptions(const EnumOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumOptions) @@ -6547,10 +7038,20 @@ EnumOptions::~EnumOptions() { } void EnumOptions::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void EnumOptions::ArenaDtor(void* object) { + EnumOptions* _this = reinterpret_cast< EnumOptions* >(object); + (void)_this; +} +void EnumOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void EnumOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -6568,8 +7069,8 @@ const EnumOptions& EnumOptions::default_instance() { EnumOptions* EnumOptions::default_instance_ = NULL; -EnumOptions* EnumOptions::New() const { - return new EnumOptions; +EnumOptions* EnumOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void EnumOptions::Clear() { @@ -6591,7 +7092,9 @@ void EnumOptions::Clear() { uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool EnumOptions::MergePartialFromCodedStream( @@ -6697,7 +7200,7 @@ void EnumOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -6728,7 +7231,7 @@ void EnumOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -6739,7 +7242,7 @@ void EnumOptions::SerializeWithCachedSizes( int EnumOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bits_[0 / 32] & 3) { // optional bool allow_alias = 2; if (has_allow_alias()) { total_size += 1 + 1; @@ -6761,7 +7264,7 @@ int EnumOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -6796,7 +7299,9 @@ void EnumOptions::MergeFrom(const EnumOptions& from) { } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -6819,16 +7324,30 @@ bool EnumOptions::IsInitialized() const { } void EnumOptions::Swap(EnumOptions* other) { - if (other != this) { - std::swap(allow_alias_, other->allow_alias_); - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + EnumOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void EnumOptions::UnsafeArenaSwap(EnumOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void EnumOptions::InternalSwap(EnumOptions* other) { + std::swap(allow_alias_, other->allow_alias_); + std::swap(deprecated_, other->deprecated_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); +} ::google::protobuf::Metadata EnumOptions::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -6847,16 +7366,26 @@ const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumValueOptions::EnumValueOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumValueOptions) } +EnumValueOptions::EnumValueOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueOptions) +} + void EnumValueOptions::InitAsDefaultInstance() { } EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueOptions) @@ -6874,10 +7403,20 @@ EnumValueOptions::~EnumValueOptions() { } void EnumValueOptions::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void EnumValueOptions::ArenaDtor(void* object) { + EnumValueOptions* _this = reinterpret_cast< EnumValueOptions* >(object); + (void)_this; +} +void EnumValueOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void EnumValueOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -6895,8 +7434,8 @@ const EnumValueOptions& EnumValueOptions::default_instance() { EnumValueOptions* EnumValueOptions::default_instance_ = NULL; -EnumValueOptions* EnumValueOptions::New() const { - return new EnumValueOptions; +EnumValueOptions* EnumValueOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void EnumValueOptions::Clear() { @@ -6904,7 +7443,9 @@ void EnumValueOptions::Clear() { deprecated_ = false; uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool EnumValueOptions::MergePartialFromCodedStream( @@ -6990,7 +7531,7 @@ void EnumValueOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -7016,7 +7557,7 @@ void EnumValueOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -7027,13 +7568,11 @@ void EnumValueOptions::SerializeWithCachedSizes( int EnumValueOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional bool deprecated = 1 [default = false]; - if (has_deprecated()) { - total_size += 1 + 1; - } - + // optional bool deprecated = 1 [default = false]; + if (has_deprecated()) { + total_size += 1 + 1; } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); for (int i = 0; i < this->uninterpreted_option_size(); i++) { @@ -7044,7 +7583,7 @@ int EnumValueOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -7076,7 +7615,9 @@ void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -7099,15 +7640,29 @@ bool EnumValueOptions::IsInitialized() const { } void EnumValueOptions::Swap(EnumValueOptions* other) { - if (other != this) { - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + EnumValueOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void EnumValueOptions::UnsafeArenaSwap(EnumValueOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void EnumValueOptions::InternalSwap(EnumValueOptions* other) { + std::swap(deprecated_, other->deprecated_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); +} ::google::protobuf::Metadata EnumValueOptions::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -7126,16 +7681,26 @@ const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER ServiceOptions::ServiceOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.ServiceOptions) } +ServiceOptions::ServiceOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceOptions) +} + void ServiceOptions::InitAsDefaultInstance() { } ServiceOptions::ServiceOptions(const ServiceOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceOptions) @@ -7153,10 +7718,20 @@ ServiceOptions::~ServiceOptions() { } void ServiceOptions::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void ServiceOptions::ArenaDtor(void* object) { + ServiceOptions* _this = reinterpret_cast< ServiceOptions* >(object); + (void)_this; +} +void ServiceOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void ServiceOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -7174,8 +7749,8 @@ const ServiceOptions& ServiceOptions::default_instance() { ServiceOptions* ServiceOptions::default_instance_ = NULL; -ServiceOptions* ServiceOptions::New() const { - return new ServiceOptions; +ServiceOptions* ServiceOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void ServiceOptions::Clear() { @@ -7183,7 +7758,9 @@ void ServiceOptions::Clear() { deprecated_ = false; uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool ServiceOptions::MergePartialFromCodedStream( @@ -7269,7 +7846,7 @@ void ServiceOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -7295,7 +7872,7 @@ void ServiceOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -7306,13 +7883,11 @@ void ServiceOptions::SerializeWithCachedSizes( int ServiceOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional bool deprecated = 33 [default = false]; - if (has_deprecated()) { - total_size += 2 + 1; - } - + // optional bool deprecated = 33 [default = false]; + if (has_deprecated()) { + total_size += 2 + 1; } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); for (int i = 0; i < this->uninterpreted_option_size(); i++) { @@ -7323,7 +7898,7 @@ int ServiceOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -7355,7 +7930,9 @@ void ServiceOptions::MergeFrom(const ServiceOptions& from) { } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -7378,15 +7955,29 @@ bool ServiceOptions::IsInitialized() const { } void ServiceOptions::Swap(ServiceOptions* other) { - if (other != this) { - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + ServiceOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void ServiceOptions::UnsafeArenaSwap(ServiceOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void ServiceOptions::InternalSwap(ServiceOptions* other) { + std::swap(deprecated_, other->deprecated_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); +} ::google::protobuf::Metadata ServiceOptions::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -7405,16 +7996,26 @@ const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MethodOptions::MethodOptions() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MethodOptions) } +MethodOptions::MethodOptions(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _extensions_(arena), _internal_metadata_(arena), + uninterpreted_option_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodOptions) +} + void MethodOptions::InitAsDefaultInstance() { } MethodOptions::MethodOptions(const MethodOptions& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodOptions) @@ -7432,10 +8033,20 @@ MethodOptions::~MethodOptions() { } void MethodOptions::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void MethodOptions::ArenaDtor(void* object) { + MethodOptions* _this = reinterpret_cast< MethodOptions* >(object); + (void)_this; +} +void MethodOptions::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void MethodOptions::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -7453,8 +8064,8 @@ const MethodOptions& MethodOptions::default_instance() { MethodOptions* MethodOptions::default_instance_ = NULL; -MethodOptions* MethodOptions::New() const { - return new MethodOptions; +MethodOptions* MethodOptions::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void MethodOptions::Clear() { @@ -7462,7 +8073,9 @@ void MethodOptions::Clear() { deprecated_ = false; uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool MethodOptions::MergePartialFromCodedStream( @@ -7548,7 +8161,7 @@ void MethodOptions::SerializeWithCachedSizes( _extensions_.SerializeWithCachedSizes( 1000, 536870912, output); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -7574,7 +8187,7 @@ void MethodOptions::SerializeWithCachedSizes( target = _extensions_.SerializeWithCachedSizesToArray( 1000, 536870912, target); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -7585,13 +8198,11 @@ void MethodOptions::SerializeWithCachedSizes( int MethodOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional bool deprecated = 33 [default = false]; - if (has_deprecated()) { - total_size += 2 + 1; - } - + // optional bool deprecated = 33 [default = false]; + if (has_deprecated()) { + total_size += 2 + 1; } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); for (int i = 0; i < this->uninterpreted_option_size(); i++) { @@ -7602,7 +8213,7 @@ int MethodOptions::ByteSize() const { total_size += _extensions_.ByteSize(); - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -7634,7 +8245,9 @@ void MethodOptions::MergeFrom(const MethodOptions& from) { } } _extensions_.MergeFrom(from._extensions_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) { @@ -7657,15 +8270,29 @@ bool MethodOptions::IsInitialized() const { } void MethodOptions::Swap(MethodOptions* other) { - if (other != this) { - std::swap(deprecated_, other->deprecated_); - uninterpreted_option_.Swap(&other->uninterpreted_option_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - _unknown_fields_.Swap(&other->_unknown_fields_); - std::swap(_cached_size_, other->_cached_size_); - _extensions_.Swap(&other->_extensions_); + if (other == this) return; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + MethodOptions temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void MethodOptions::UnsafeArenaSwap(MethodOptions* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void MethodOptions::InternalSwap(MethodOptions* other) { + std::swap(deprecated_, other->deprecated_); + uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); + _extensions_.Swap(&other->_extensions_); +} ::google::protobuf::Metadata MethodOptions::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -7684,16 +8311,25 @@ const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER UninterpretedOption_NamePart::UninterpretedOption_NamePart() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption.NamePart) } +UninterpretedOption_NamePart::UninterpretedOption_NamePart(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption.NamePart) +} + void UninterpretedOption_NamePart::InitAsDefaultInstance() { } UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption.NamePart) @@ -7702,7 +8338,7 @@ UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOp void UninterpretedOption_NamePart::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + name_part_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); is_extension_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -7713,13 +8349,21 @@ UninterpretedOption_NamePart::~UninterpretedOption_NamePart() { } void UninterpretedOption_NamePart::SharedDtor() { - if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_part_; + if (GetArenaNoVirtual() != NULL) { + return; } + + name_part_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void UninterpretedOption_NamePart::ArenaDtor(void* object) { + UninterpretedOption_NamePart* _this = reinterpret_cast< UninterpretedOption_NamePart* >(object); + (void)_this; +} +void UninterpretedOption_NamePart::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void UninterpretedOption_NamePart::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -7737,21 +8381,21 @@ const UninterpretedOption_NamePart& UninterpretedOption_NamePart::default_instan UninterpretedOption_NamePart* UninterpretedOption_NamePart::default_instance_ = NULL; -UninterpretedOption_NamePart* UninterpretedOption_NamePart::New() const { - return new UninterpretedOption_NamePart; +UninterpretedOption_NamePart* UninterpretedOption_NamePart::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void UninterpretedOption_NamePart::Clear() { if (_has_bits_[0 / 32] & 3) { if (has_name_part()) { - if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_->clear(); - } + name_part_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } is_extension_ = false; } ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool UninterpretedOption_NamePart::MergePartialFromCodedStream( @@ -7772,7 +8416,7 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name_part().data(), this->name_part().length(), ::google::protobuf::internal::WireFormat::PARSE, - "name_part"); + "google.protobuf.UninterpretedOption.NamePart.name_part"); } else { goto handle_unusual; } @@ -7825,7 +8469,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name_part().data(), this->name_part().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name_part"); + "google.protobuf.UninterpretedOption.NamePart.name_part"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name_part(), output); } @@ -7835,7 +8479,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->is_extension(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -7850,7 +8494,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->name_part().data(), this->name_part().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "name_part"); + "google.protobuf.UninterpretedOption.NamePart.name_part"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 1, this->name_part(), target); @@ -7861,7 +8505,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->is_extension(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -7869,24 +8513,39 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( return target; } +int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { + int total_size = 0; + + if (has_name_part()) { + // required string name_part = 1; + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name_part()); + } + + if (has_is_extension()) { + // required bool is_extension = 2; + total_size += 1 + 1; + } + + return total_size; +} int UninterpretedOption_NamePart::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) { // All required fields are present. // required string name_part = 1; - if (has_name_part()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->name_part()); - } + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name_part()); // required bool is_extension = 2; - if (has_is_extension()) { - total_size += 1 + 1; - } + total_size += 1 + 1; + } else { + total_size += RequiredFieldsByteSizeFallback(); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -7919,7 +8578,9 @@ void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& set_is_extension(from.is_extension()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void UninterpretedOption_NamePart::CopyFrom(const ::google::protobuf::Message& from) { @@ -7941,14 +8602,28 @@ bool UninterpretedOption_NamePart::IsInitialized() const { } void UninterpretedOption_NamePart::Swap(UninterpretedOption_NamePart* other) { - if (other != this) { - std::swap(name_part_, other->name_part_); - std::swap(is_extension_, other->is_extension_); - 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 { + UninterpretedOption_NamePart temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void UninterpretedOption_NamePart::UnsafeArenaSwap(UninterpretedOption_NamePart* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* other) { + name_part_.Swap(&other->name_part_); + std::swap(is_extension_, other->is_extension_); + 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 UninterpretedOption_NamePart::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -7972,16 +8647,26 @@ const int UninterpretedOption::kAggregateValueFieldNumber; #endif // !_MSC_VER UninterpretedOption::UninterpretedOption() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption) } +UninterpretedOption::UninterpretedOption(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + name_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption) +} + void UninterpretedOption::InitAsDefaultInstance() { } UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption) @@ -7990,12 +8675,12 @@ UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) void UninterpretedOption::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + identifier_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); positive_int_value_ = GOOGLE_ULONGLONG(0); negative_int_value_ = GOOGLE_LONGLONG(0); double_value_ = 0; - string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + aggregate_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -8005,19 +8690,23 @@ UninterpretedOption::~UninterpretedOption() { } void UninterpretedOption::SharedDtor() { - if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete identifier_value_; - } - if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete string_value_; - } - if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete aggregate_value_; + if (GetArenaNoVirtual() != NULL) { + return; } + + identifier_value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + string_value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + aggregate_value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void UninterpretedOption::ArenaDtor(void* object) { + UninterpretedOption* _this = reinterpret_cast< UninterpretedOption* >(object); + (void)_this; +} +void UninterpretedOption::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void UninterpretedOption::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -8035,8 +8724,8 @@ const UninterpretedOption& UninterpretedOption::default_instance() { UninterpretedOption* UninterpretedOption::default_instance_ = NULL; -UninterpretedOption* UninterpretedOption::New() const { - return new UninterpretedOption; +UninterpretedOption* UninterpretedOption::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void UninterpretedOption::Clear() { @@ -8053,19 +8742,13 @@ void UninterpretedOption::Clear() { if (_has_bits_[0 / 32] & 126) { ZR_(positive_int_value_, double_value_); if (has_identifier_value()) { - if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_->clear(); - } + identifier_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_string_value()) { - if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_->clear(); - } + string_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_aggregate_value()) { - if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_->clear(); - } + aggregate_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } } @@ -8074,7 +8757,9 @@ void UninterpretedOption::Clear() { name_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool UninterpretedOption::MergePartialFromCodedStream( @@ -8110,7 +8795,7 @@ bool UninterpretedOption::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->identifier_value().data(), this->identifier_value().length(), ::google::protobuf::internal::WireFormat::PARSE, - "identifier_value"); + "google.protobuf.UninterpretedOption.identifier_value"); } else { goto handle_unusual; } @@ -8185,7 +8870,7 @@ bool UninterpretedOption::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->aggregate_value().data(), this->aggregate_value().length(), ::google::protobuf::internal::WireFormat::PARSE, - "aggregate_value"); + "google.protobuf.UninterpretedOption.aggregate_value"); } else { goto handle_unusual; } @@ -8229,7 +8914,7 @@ void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->identifier_value().data(), this->identifier_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "identifier_value"); + "google.protobuf.UninterpretedOption.identifier_value"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 3, this->identifier_value(), output); } @@ -8260,12 +8945,12 @@ void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->aggregate_value().data(), this->aggregate_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "aggregate_value"); + "google.protobuf.UninterpretedOption.aggregate_value"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 8, this->aggregate_value(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -8287,7 +8972,7 @@ void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->identifier_value().data(), this->identifier_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "identifier_value"); + "google.protobuf.UninterpretedOption.identifier_value"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 3, this->identifier_value(), target); @@ -8320,13 +9005,13 @@ void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->aggregate_value().data(), this->aggregate_value().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "aggregate_value"); + "google.protobuf.UninterpretedOption.aggregate_value"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 8, this->aggregate_value(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -8337,7 +9022,7 @@ void UninterpretedOption::SerializeWithCachedSizes( int UninterpretedOption::ByteSize() const { int total_size = 0; - if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (_has_bits_[1 / 32] & 126) { // optional string identifier_value = 3; if (has_identifier_value()) { total_size += 1 + @@ -8387,7 +9072,7 @@ int UninterpretedOption::ByteSize() const { this->name(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -8433,7 +9118,9 @@ void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { set_aggregate_value(from.aggregate_value()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void UninterpretedOption::CopyFrom(const ::google::protobuf::Message& from) { @@ -8455,18 +9142,32 @@ bool UninterpretedOption::IsInitialized() const { } void UninterpretedOption::Swap(UninterpretedOption* other) { - if (other != this) { - name_.Swap(&other->name_); - std::swap(identifier_value_, other->identifier_value_); - std::swap(positive_int_value_, other->positive_int_value_); - std::swap(negative_int_value_, other->negative_int_value_); - std::swap(double_value_, other->double_value_); - std::swap(string_value_, other->string_value_); - std::swap(aggregate_value_, other->aggregate_value_); - 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 { + UninterpretedOption temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void UninterpretedOption::UnsafeArenaSwap(UninterpretedOption* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void UninterpretedOption::InternalSwap(UninterpretedOption* other) { + name_.UnsafeArenaSwap(&other->name_); + identifier_value_.Swap(&other->identifier_value_); + std::swap(positive_int_value_, other->positive_int_value_); + std::swap(negative_int_value_, other->negative_int_value_); + std::swap(double_value_, other->double_value_); + string_value_.Swap(&other->string_value_); + aggregate_value_.Swap(&other->aggregate_value_); + 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 UninterpretedOption::GetMetadata() const { @@ -8488,16 +9189,27 @@ const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber; #endif // !_MSC_VER SourceCodeInfo_Location::SourceCodeInfo_Location() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo.Location) } +SourceCodeInfo_Location::SourceCodeInfo_Location(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + path_(arena), + span_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo.Location) +} + void SourceCodeInfo_Location::InitAsDefaultInstance() { } SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo.Location) @@ -8506,8 +9218,8 @@ SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& void SourceCodeInfo_Location::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; - leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + leading_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + trailing_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -8517,16 +9229,22 @@ SourceCodeInfo_Location::~SourceCodeInfo_Location() { } void SourceCodeInfo_Location::SharedDtor() { - if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete leading_comments_; - } - if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete trailing_comments_; + if (GetArenaNoVirtual() != NULL) { + return; } + + leading_comments_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + trailing_comments_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); if (this != default_instance_) { } } +void SourceCodeInfo_Location::ArenaDtor(void* object) { + SourceCodeInfo_Location* _this = reinterpret_cast< SourceCodeInfo_Location* >(object); + (void)_this; +} +void SourceCodeInfo_Location::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void SourceCodeInfo_Location::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -8544,27 +9262,25 @@ const SourceCodeInfo_Location& SourceCodeInfo_Location::default_instance() { SourceCodeInfo_Location* SourceCodeInfo_Location::default_instance_ = NULL; -SourceCodeInfo_Location* SourceCodeInfo_Location::New() const { - return new SourceCodeInfo_Location; +SourceCodeInfo_Location* SourceCodeInfo_Location::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void SourceCodeInfo_Location::Clear() { if (_has_bits_[0 / 32] & 12) { if (has_leading_comments()) { - if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_->clear(); - } + leading_comments_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } if (has_trailing_comments()) { - if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_->clear(); - } + trailing_comments_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } } path_.Clear(); span_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool SourceCodeInfo_Location::MergePartialFromCodedStream( @@ -8621,7 +9337,7 @@ bool SourceCodeInfo_Location::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->leading_comments().data(), this->leading_comments().length(), ::google::protobuf::internal::WireFormat::PARSE, - "leading_comments"); + "google.protobuf.SourceCodeInfo.Location.leading_comments"); } else { goto handle_unusual; } @@ -8638,7 +9354,7 @@ bool SourceCodeInfo_Location::MergePartialFromCodedStream( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->trailing_comments().data(), this->trailing_comments().length(), ::google::protobuf::internal::WireFormat::PARSE, - "trailing_comments"); + "google.protobuf.SourceCodeInfo.Location.trailing_comments"); } else { goto handle_unusual; } @@ -8696,7 +9412,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->leading_comments().data(), this->leading_comments().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "leading_comments"); + "google.protobuf.SourceCodeInfo.Location.leading_comments"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 3, this->leading_comments(), output); } @@ -8706,12 +9422,12 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->trailing_comments().data(), this->trailing_comments().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "trailing_comments"); + "google.protobuf.SourceCodeInfo.Location.trailing_comments"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 4, this->trailing_comments(), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -8754,7 +9470,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->leading_comments().data(), this->leading_comments().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "leading_comments"); + "google.protobuf.SourceCodeInfo.Location.leading_comments"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 3, this->leading_comments(), target); @@ -8765,13 +9481,13 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( this->trailing_comments().data(), this->trailing_comments().length(), ::google::protobuf::internal::WireFormat::SERIALIZE, - "trailing_comments"); + "google.protobuf.SourceCodeInfo.Location.trailing_comments"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 4, this->trailing_comments(), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -8782,7 +9498,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( int SourceCodeInfo_Location::ByteSize() const { int total_size = 0; - if (_has_bits_[2 / 32] & (0xffu << (2 % 32))) { + if (_has_bits_[2 / 32] & 12) { // optional string leading_comments = 3; if (has_leading_comments()) { total_size += 1 + @@ -8832,7 +9548,7 @@ int SourceCodeInfo_Location::ByteSize() const { total_size += data_size; } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -8867,7 +9583,9 @@ void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { set_trailing_comments(from.trailing_comments()); } } - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) { @@ -8888,16 +9606,30 @@ bool SourceCodeInfo_Location::IsInitialized() const { } void SourceCodeInfo_Location::Swap(SourceCodeInfo_Location* other) { - if (other != this) { - path_.Swap(&other->path_); - span_.Swap(&other->span_); - std::swap(leading_comments_, other->leading_comments_); - std::swap(trailing_comments_, other->trailing_comments_); - 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 { + SourceCodeInfo_Location temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); } } +void SourceCodeInfo_Location::UnsafeArenaSwap(SourceCodeInfo_Location* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) { + path_.UnsafeArenaSwap(&other->path_); + span_.UnsafeArenaSwap(&other->span_); + leading_comments_.Swap(&other->leading_comments_); + trailing_comments_.Swap(&other->trailing_comments_); + 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 SourceCodeInfo_Location::GetMetadata() const { protobuf_AssignDescriptorsOnce(); @@ -8915,16 +9647,26 @@ const int SourceCodeInfo::kLocationFieldNumber; #endif // !_MSC_VER SourceCodeInfo::SourceCodeInfo() - : ::google::protobuf::Message() { + : ::google::protobuf::Message() , _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo) } +SourceCodeInfo::SourceCodeInfo(::google::protobuf::Arena* arena) + : ::google::protobuf::Message(), + _internal_metadata_(arena), + location_(arena) { + SharedCtor(); + RegisterArenaDtor(arena); + // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo) +} + void SourceCodeInfo::InitAsDefaultInstance() { } SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from) - : ::google::protobuf::Message() { + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo) @@ -8941,10 +9683,20 @@ SourceCodeInfo::~SourceCodeInfo() { } void SourceCodeInfo::SharedDtor() { + if (GetArenaNoVirtual() != NULL) { + return; + } + if (this != default_instance_) { } } +void SourceCodeInfo::ArenaDtor(void* object) { + SourceCodeInfo* _this = reinterpret_cast< SourceCodeInfo* >(object); + (void)_this; +} +void SourceCodeInfo::RegisterArenaDtor(::google::protobuf::Arena* arena) { +} void SourceCodeInfo::SetCachedSize(int size) const { GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = size; @@ -8962,14 +9714,16 @@ const SourceCodeInfo& SourceCodeInfo::default_instance() { SourceCodeInfo* SourceCodeInfo::default_instance_ = NULL; -SourceCodeInfo* SourceCodeInfo::New() const { - return new SourceCodeInfo; +SourceCodeInfo* SourceCodeInfo::New(::google::protobuf::Arena* arena) const { + return ::google::protobuf::Arena::CreateMessage(arena); } void SourceCodeInfo::Clear() { location_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); - mutable_unknown_fields()->Clear(); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } } bool SourceCodeInfo::MergePartialFromCodedStream( @@ -9027,7 +9781,7 @@ void SourceCodeInfo::SerializeWithCachedSizes( 1, this->location(i), output); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); } @@ -9044,7 +9798,7 @@ void SourceCodeInfo::SerializeWithCachedSizes( 1, this->location(i), target); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); } @@ -9063,7 +9817,7 @@ int SourceCodeInfo::ByteSize() const { this->location(i)); } - if (!unknown_fields().empty()) { + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); @@ -9089,7 +9843,9 @@ void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { GOOGLE_CHECK_NE(&from, this); location_.MergeFrom(from.location_); - mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } } void SourceCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { @@ -9110,12 +9866,26 @@ bool SourceCodeInfo::IsInitialized() const { } void SourceCodeInfo::Swap(SourceCodeInfo* other) { - if (other != this) { - location_.Swap(&other->location_); - 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 { + SourceCodeInfo temp; + temp.MergeFrom(*this); + CopyFrom(*other); + other->CopyFrom(temp); + } +} +void SourceCodeInfo::UnsafeArenaSwap(SourceCodeInfo* other) { + if (other == this) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); +} +void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) { + location_.UnsafeArenaSwap(&other->location_); + 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 SourceCodeInfo::GetMetadata() const { diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index dd721be9..295b53f3 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -5,6 +5,7 @@ #define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED #include +#include #include @@ -19,7 +20,10 @@ #error regenerate this file with a newer version of protoc. #endif +#include +#include #include +#include #include #include #include @@ -167,21 +171,28 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : 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 FileDescriptorSet& default_instance(); + void UnsafeArenaSwap(FileDescriptorSet* other); void Swap(FileDescriptorSet* other); // implements Message ---------------------------------------------- - FileDescriptorSet* New() const; + inline FileDescriptorSet* New() const { return New(NULL); } + + FileDescriptorSet* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const FileDescriptorSet& from); @@ -200,7 +211,21 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(FileDescriptorSet* other); + protected: + explicit FileDescriptorSet(::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 ---------------------------------------------------- @@ -222,8 +247,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: - ::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< ::google::protobuf::FileDescriptorProto > file_; @@ -249,21 +276,28 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : 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 FileDescriptorProto& default_instance(); + void UnsafeArenaSwap(FileDescriptorProto* other); void Swap(FileDescriptorProto* other); // implements Message ---------------------------------------------- - FileDescriptorProto* New() const; + inline FileDescriptorProto* New() const { return New(NULL); } + + FileDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const FileDescriptorProto& from); @@ -282,7 +316,21 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(FileDescriptorProto* other); + protected: + explicit FileDescriptorProto(::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 ---------------------------------------------------- @@ -300,6 +348,9 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag 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 package = 2; inline bool has_package() const; @@ -312,6 +363,9 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline ::std::string* mutable_package(); inline ::std::string* release_package(); inline void set_allocated_package(::std::string* package); + inline ::std::string* unsafe_arena_release_package(); + inline void unsafe_arena_set_allocated_package( + ::std::string* package); // repeated string dependency = 3; inline int dependency_size() const; @@ -409,6 +463,9 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline ::google::protobuf::FileOptions* mutable_options(); inline ::google::protobuf::FileOptions* release_options(); inline void set_allocated_options(::google::protobuf::FileOptions* options); + inline ::google::protobuf::FileOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::FileOptions* options); // optional .google.protobuf.SourceCodeInfo source_code_info = 9; inline bool has_source_code_info() const; @@ -418,6 +475,24 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info(); inline ::google::protobuf::SourceCodeInfo* release_source_code_info(); inline void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info); + inline ::google::protobuf::SourceCodeInfo* unsafe_arena_release_source_code_info(); + inline void unsafe_arena_set_allocated_source_code_info( + ::google::protobuf::SourceCodeInfo* source_code_info); + + // optional string syntax = 12; + inline bool has_syntax() const; + inline void clear_syntax(); + static const int kSyntaxFieldNumber = 12; + inline const ::std::string& syntax() const; + inline void set_syntax(const ::std::string& value); + inline void set_syntax(const char* value); + inline void set_syntax(const char* value, size_t size); + inline ::std::string* mutable_syntax(); + inline ::std::string* release_syntax(); + inline void set_allocated_syntax(::std::string* syntax); + inline ::std::string* unsafe_arena_release_syntax(); + inline void unsafe_arena_set_allocated_syntax( + ::std::string* syntax); // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) private: @@ -429,13 +504,17 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline void clear_has_options(); inline void set_has_source_code_info(); inline void clear_has_source_code_info(); + inline void set_has_syntax(); + inline void clear_has_syntax(); - ::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* package_; + ::google::protobuf::internal::ArenaStringPtr name_; + ::google::protobuf::internal::ArenaStringPtr package_; ::google::protobuf::RepeatedPtrField< ::std::string> dependency_; ::google::protobuf::RepeatedField< ::google::protobuf::int32 > public_dependency_; ::google::protobuf::RepeatedField< ::google::protobuf::int32 > weak_dependency_; @@ -445,6 +524,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; ::google::protobuf::FileOptions* options_; ::google::protobuf::SourceCodeInfo* source_code_info_; + ::google::protobuf::internal::ArenaStringPtr syntax_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -467,21 +547,28 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto } 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 DescriptorProto_ExtensionRange& default_instance(); + void UnsafeArenaSwap(DescriptorProto_ExtensionRange* other); void Swap(DescriptorProto_ExtensionRange* other); // implements Message ---------------------------------------------- - DescriptorProto_ExtensionRange* New() const; + inline DescriptorProto_ExtensionRange* New() const { return New(NULL); } + + DescriptorProto_ExtensionRange* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const DescriptorProto_ExtensionRange& from); @@ -500,7 +587,21 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(DescriptorProto_ExtensionRange* other); + protected: + explicit DescriptorProto_ExtensionRange(::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 ---------------------------------------------------- @@ -528,8 +629,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto inline void set_has_end(); inline void clear_has_end(); - ::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::int32 start_; @@ -556,21 +659,28 @@ class LIBPROTOBUF_EXPORT DescriptorProto : 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 DescriptorProto& default_instance(); + void UnsafeArenaSwap(DescriptorProto* other); void Swap(DescriptorProto* other); // implements Message ---------------------------------------------- - DescriptorProto* New() const; + inline DescriptorProto* New() const { return New(NULL); } + + DescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const DescriptorProto& from); @@ -589,7 +699,21 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(DescriptorProto* other); + protected: + explicit DescriptorProto(::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 ---------------------------------------------------- @@ -609,6 +733,9 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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); // repeated .google.protobuf.FieldDescriptorProto field = 2; inline int field_size() const; @@ -690,6 +817,9 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline ::google::protobuf::MessageOptions* mutable_options(); inline ::google::protobuf::MessageOptions* release_options(); inline void set_allocated_options(::google::protobuf::MessageOptions* options); + inline ::google::protobuf::MessageOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::MessageOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) private: @@ -698,11 +828,13 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline void set_has_options(); inline void clear_has_options(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > nested_type_; @@ -732,21 +864,28 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa } 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 FieldDescriptorProto& default_instance(); + void UnsafeArenaSwap(FieldDescriptorProto* other); void Swap(FieldDescriptorProto* other); // implements Message ---------------------------------------------- - FieldDescriptorProto* New() const; + inline FieldDescriptorProto* New() const { return New(NULL); } + + FieldDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const FieldDescriptorProto& from); @@ -765,7 +904,21 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(FieldDescriptorProto* other); + protected: + explicit FieldDescriptorProto(::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 ---------------------------------------------------- @@ -848,6 +1001,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa 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 int32 number = 3; inline bool has_number() const; @@ -881,6 +1037,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline ::std::string* mutable_type_name(); inline ::std::string* release_type_name(); inline void set_allocated_type_name(::std::string* type_name); + inline ::std::string* unsafe_arena_release_type_name(); + inline void unsafe_arena_set_allocated_type_name( + ::std::string* type_name); // optional string extendee = 2; inline bool has_extendee() const; @@ -893,6 +1052,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline ::std::string* mutable_extendee(); inline ::std::string* release_extendee(); inline void set_allocated_extendee(::std::string* extendee); + inline ::std::string* unsafe_arena_release_extendee(); + inline void unsafe_arena_set_allocated_extendee( + ::std::string* extendee); // optional string default_value = 7; inline bool has_default_value() const; @@ -905,6 +1067,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline ::std::string* mutable_default_value(); inline ::std::string* release_default_value(); inline void set_allocated_default_value(::std::string* default_value); + inline ::std::string* unsafe_arena_release_default_value(); + inline void unsafe_arena_set_allocated_default_value( + ::std::string* default_value); // optional int32 oneof_index = 9; inline bool has_oneof_index() const; @@ -921,6 +1086,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline ::google::protobuf::FieldOptions* mutable_options(); inline ::google::protobuf::FieldOptions* release_options(); inline void set_allocated_options(::google::protobuf::FieldOptions* options); + inline ::google::protobuf::FieldOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::FieldOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) private: @@ -943,18 +1111,20 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline void set_has_options(); inline void clear_has_options(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::int32 number_; int label_; - ::std::string* type_name_; - ::std::string* extendee_; + ::google::protobuf::internal::ArenaStringPtr type_name_; + ::google::protobuf::internal::ArenaStringPtr extendee_; int type_; ::google::protobuf::int32 oneof_index_; - ::std::string* default_value_; + ::google::protobuf::internal::ArenaStringPtr default_value_; ::google::protobuf::FieldOptions* options_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -978,21 +1148,28 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa } 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 OneofDescriptorProto& default_instance(); + void UnsafeArenaSwap(OneofDescriptorProto* other); void Swap(OneofDescriptorProto* other); // implements Message ---------------------------------------------- - OneofDescriptorProto* New() const; + inline OneofDescriptorProto* New() const { return New(NULL); } + + OneofDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const OneofDescriptorProto& from); @@ -1011,7 +1188,21 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(OneofDescriptorProto* other); + protected: + explicit OneofDescriptorProto(::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 ---------------------------------------------------- @@ -1029,17 +1220,22 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa 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); // @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto) private: inline void set_has_name(); inline void clear_has_name(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1062,21 +1258,28 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : 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 EnumDescriptorProto& default_instance(); + void UnsafeArenaSwap(EnumDescriptorProto* other); void Swap(EnumDescriptorProto* other); // implements Message ---------------------------------------------- - EnumDescriptorProto* New() const; + inline EnumDescriptorProto* New() const { return New(NULL); } + + EnumDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const EnumDescriptorProto& from); @@ -1095,7 +1298,21 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(EnumDescriptorProto* other); + protected: + explicit EnumDescriptorProto(::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 ---------------------------------------------------- @@ -1113,6 +1330,9 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag 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); // repeated .google.protobuf.EnumValueDescriptorProto value = 2; inline int value_size() const; @@ -1134,6 +1354,9 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline ::google::protobuf::EnumOptions* mutable_options(); inline ::google::protobuf::EnumOptions* release_options(); inline void set_allocated_options(::google::protobuf::EnumOptions* options); + inline ::google::protobuf::EnumOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::EnumOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) private: @@ -1142,11 +1365,13 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline void set_has_options(); inline void clear_has_options(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_; ::google::protobuf::EnumOptions* options_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1171,21 +1396,28 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : 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 EnumValueDescriptorProto& default_instance(); + void UnsafeArenaSwap(EnumValueDescriptorProto* other); void Swap(EnumValueDescriptorProto* other); // implements Message ---------------------------------------------- - EnumValueDescriptorProto* New() const; + inline EnumValueDescriptorProto* New() const { return New(NULL); } + + EnumValueDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const EnumValueDescriptorProto& from); @@ -1204,7 +1436,21 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(EnumValueDescriptorProto* other); + protected: + explicit EnumValueDescriptorProto(::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 ---------------------------------------------------- @@ -1222,6 +1468,9 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : 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 int32 number = 2; inline bool has_number() const; @@ -1238,6 +1487,9 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline ::google::protobuf::EnumValueOptions* mutable_options(); inline ::google::protobuf::EnumValueOptions* release_options(); inline void set_allocated_options(::google::protobuf::EnumValueOptions* options); + inline ::google::protobuf::EnumValueOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::EnumValueOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) private: @@ -1248,11 +1500,13 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline void set_has_options(); inline void clear_has_options(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::EnumValueOptions* options_; ::google::protobuf::int32 number_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1277,21 +1531,28 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes } 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 ServiceDescriptorProto& default_instance(); + void UnsafeArenaSwap(ServiceDescriptorProto* other); void Swap(ServiceDescriptorProto* other); // implements Message ---------------------------------------------- - ServiceDescriptorProto* New() const; + inline ServiceDescriptorProto* New() const { return New(NULL); } + + ServiceDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const ServiceDescriptorProto& from); @@ -1310,7 +1571,21 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(ServiceDescriptorProto* other); + protected: + explicit ServiceDescriptorProto(::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 ---------------------------------------------------- @@ -1328,6 +1603,9 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes 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); // repeated .google.protobuf.MethodDescriptorProto method = 2; inline int method_size() const; @@ -1349,6 +1627,9 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline ::google::protobuf::ServiceOptions* mutable_options(); inline ::google::protobuf::ServiceOptions* release_options(); inline void set_allocated_options(::google::protobuf::ServiceOptions* options); + inline ::google::protobuf::ServiceOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::ServiceOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) private: @@ -1357,11 +1638,13 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline void set_has_options(); inline void clear_has_options(); - ::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_; + ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_; ::google::protobuf::ServiceOptions* options_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1386,21 +1669,28 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess } 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 MethodDescriptorProto& default_instance(); + void UnsafeArenaSwap(MethodDescriptorProto* other); void Swap(MethodDescriptorProto* other); // implements Message ---------------------------------------------- - MethodDescriptorProto* New() const; + inline MethodDescriptorProto* New() const { return New(NULL); } + + MethodDescriptorProto* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const MethodDescriptorProto& from); @@ -1419,7 +1709,21 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(MethodDescriptorProto* other); + protected: + explicit MethodDescriptorProto(::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 ---------------------------------------------------- @@ -1437,6 +1741,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess 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 input_type = 2; inline bool has_input_type() const; @@ -1449,6 +1756,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline ::std::string* mutable_input_type(); inline ::std::string* release_input_type(); inline void set_allocated_input_type(::std::string* input_type); + inline ::std::string* unsafe_arena_release_input_type(); + inline void unsafe_arena_set_allocated_input_type( + ::std::string* input_type); // optional string output_type = 3; inline bool has_output_type() const; @@ -1461,6 +1771,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline ::std::string* mutable_output_type(); inline ::std::string* release_output_type(); inline void set_allocated_output_type(::std::string* output_type); + inline ::std::string* unsafe_arena_release_output_type(); + inline void unsafe_arena_set_allocated_output_type( + ::std::string* output_type); // optional .google.protobuf.MethodOptions options = 4; inline bool has_options() const; @@ -1470,6 +1783,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline ::google::protobuf::MethodOptions* mutable_options(); inline ::google::protobuf::MethodOptions* release_options(); inline void set_allocated_options(::google::protobuf::MethodOptions* options); + inline ::google::protobuf::MethodOptions* unsafe_arena_release_options(); + inline void unsafe_arena_set_allocated_options( + ::google::protobuf::MethodOptions* options); // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) private: @@ -1482,13 +1798,15 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline void set_has_options(); inline void clear_has_options(); - ::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* input_type_; - ::std::string* output_type_; + ::google::protobuf::internal::ArenaStringPtr name_; + ::google::protobuf::internal::ArenaStringPtr input_type_; + ::google::protobuf::internal::ArenaStringPtr output_type_; ::google::protobuf::MethodOptions* options_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1512,21 +1830,28 @@ class LIBPROTOBUF_EXPORT FileOptions : 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 FileOptions& default_instance(); + void UnsafeArenaSwap(FileOptions* other); void Swap(FileOptions* other); // implements Message ---------------------------------------------- - FileOptions* New() const; + inline FileOptions* New() const { return New(NULL); } + + FileOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const FileOptions& from); @@ -1545,7 +1870,21 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(FileOptions* other); + protected: + explicit FileOptions(::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 ---------------------------------------------------- @@ -1588,6 +1927,9 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::std::string* mutable_java_package(); inline ::std::string* release_java_package(); inline void set_allocated_java_package(::std::string* java_package); + inline ::std::string* unsafe_arena_release_java_package(); + inline void unsafe_arena_set_allocated_java_package( + ::std::string* java_package); // optional string java_outer_classname = 8; inline bool has_java_outer_classname() const; @@ -1600,6 +1942,9 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::std::string* mutable_java_outer_classname(); inline ::std::string* release_java_outer_classname(); inline void set_allocated_java_outer_classname(::std::string* java_outer_classname); + inline ::std::string* unsafe_arena_release_java_outer_classname(); + inline void unsafe_arena_set_allocated_java_outer_classname( + ::std::string* java_outer_classname); // optional bool java_multiple_files = 10 [default = false]; inline bool has_java_multiple_files() const; @@ -1640,6 +1985,9 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::std::string* mutable_go_package(); inline ::std::string* release_go_package(); inline void set_allocated_go_package(::std::string* go_package); + inline ::std::string* unsafe_arena_release_go_package(); + inline void unsafe_arena_set_allocated_go_package( + ::std::string* go_package); // optional bool cc_generic_services = 16 [default = false]; inline bool has_cc_generic_services() const; @@ -1709,18 +2057,20 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { ::google::protobuf::internal::ExtensionSet _extensions_; - ::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* java_package_; - ::std::string* java_outer_classname_; + ::google::protobuf::internal::ArenaStringPtr java_package_; + ::google::protobuf::internal::ArenaStringPtr java_outer_classname_; bool java_multiple_files_; bool java_generate_equals_and_hash_; bool java_string_check_utf8_; bool cc_generic_services_; int optimize_for_; - ::std::string* go_package_; + ::google::protobuf::internal::ArenaStringPtr go_package_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool java_generic_services_; bool py_generic_services_; @@ -1747,21 +2097,28 @@ class LIBPROTOBUF_EXPORT MessageOptions : 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 MessageOptions& default_instance(); + void UnsafeArenaSwap(MessageOptions* other); void Swap(MessageOptions* other); // implements Message ---------------------------------------------- - MessageOptions* New() const; + inline MessageOptions* New() const { return New(NULL); } + + MessageOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const MessageOptions& from); @@ -1780,7 +2137,21 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(MessageOptions* other); + protected: + explicit MessageOptions(::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 ---------------------------------------------------- @@ -1808,6 +2179,13 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline bool deprecated() const; inline void set_deprecated(bool value); + // optional bool map_entry = 7; + inline bool has_map_entry() const; + inline void clear_map_entry(); + static const int kMapEntryFieldNumber = 7; + inline bool map_entry() const; + inline void set_map_entry(bool value); + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); @@ -1829,17 +2207,22 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline void clear_has_no_standard_descriptor_accessor(); inline void set_has_deprecated(); inline void clear_has_deprecated(); + inline void set_has_map_entry(); + inline void clear_has_map_entry(); ::google::protobuf::internal::ExtensionSet _extensions_; - ::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< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool message_set_wire_format_; bool no_standard_descriptor_accessor_; bool deprecated_; + bool map_entry_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -1862,21 +2245,28 @@ class LIBPROTOBUF_EXPORT FieldOptions : 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 FieldOptions& default_instance(); + void UnsafeArenaSwap(FieldOptions* other); void Swap(FieldOptions* other); // implements Message ---------------------------------------------- - FieldOptions* New() const; + inline FieldOptions* New() const { return New(NULL); } + + FieldOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const FieldOptions& from); @@ -1895,7 +2285,21 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(FieldOptions* other); + protected: + explicit FieldOptions(::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 ---------------------------------------------------- @@ -1955,18 +2359,6 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline bool deprecated() const; inline void set_deprecated(bool value); - // optional string experimental_map_key = 9; - inline bool has_experimental_map_key() const; - inline void clear_experimental_map_key(); - static const int kExperimentalMapKeyFieldNumber = 9; - inline const ::std::string& experimental_map_key() const; - inline void set_experimental_map_key(const ::std::string& value); - inline void set_experimental_map_key(const char* value); - inline void set_experimental_map_key(const char* value, size_t size); - inline ::std::string* mutable_experimental_map_key(); - inline ::std::string* release_experimental_map_key(); - inline void set_allocated_experimental_map_key(::std::string* experimental_map_key); - // optional bool weak = 10 [default = false]; inline bool has_weak() const; inline void clear_weak(); @@ -1997,15 +2389,15 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline void clear_has_lazy(); inline void set_has_deprecated(); inline void clear_has_deprecated(); - inline void set_has_experimental_map_key(); - inline void clear_has_experimental_map_key(); inline void set_has_weak(); inline void clear_has_weak(); ::google::protobuf::internal::ExtensionSet _extensions_; - ::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_; int ctype_; @@ -2013,7 +2405,6 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { bool lazy_; bool deprecated_; bool weak_; - ::std::string* experimental_map_key_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2037,21 +2428,28 @@ class LIBPROTOBUF_EXPORT EnumOptions : 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 EnumOptions& default_instance(); + void UnsafeArenaSwap(EnumOptions* other); void Swap(EnumOptions* other); // implements Message ---------------------------------------------- - EnumOptions* New() const; + inline EnumOptions* New() const { return New(NULL); } + + EnumOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const EnumOptions& from); @@ -2070,7 +2468,21 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(EnumOptions* other); + protected: + explicit EnumOptions(::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 ---------------------------------------------------- @@ -2113,8 +2525,10 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { ::google::protobuf::internal::ExtensionSet _extensions_; - ::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< ::google::protobuf::UninterpretedOption > uninterpreted_option_; @@ -2142,21 +2556,28 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : 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 EnumValueOptions& default_instance(); + void UnsafeArenaSwap(EnumValueOptions* other); void Swap(EnumValueOptions* other); // implements Message ---------------------------------------------- - EnumValueOptions* New() const; + inline EnumValueOptions* New() const { return New(NULL); } + + EnumValueOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const EnumValueOptions& from); @@ -2175,7 +2596,21 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(EnumValueOptions* other); + protected: + explicit EnumValueOptions(::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 ---------------------------------------------------- @@ -2209,8 +2644,10 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { ::google::protobuf::internal::ExtensionSet _extensions_; - ::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< ::google::protobuf::UninterpretedOption > uninterpreted_option_; @@ -2237,21 +2674,28 @@ class LIBPROTOBUF_EXPORT ServiceOptions : 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 ServiceOptions& default_instance(); + void UnsafeArenaSwap(ServiceOptions* other); void Swap(ServiceOptions* other); // implements Message ---------------------------------------------- - ServiceOptions* New() const; + inline ServiceOptions* New() const { return New(NULL); } + + ServiceOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const ServiceOptions& from); @@ -2270,7 +2714,21 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(ServiceOptions* other); + protected: + explicit ServiceOptions(::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 ---------------------------------------------------- @@ -2304,8 +2762,10 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { ::google::protobuf::internal::ExtensionSet _extensions_; - ::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< ::google::protobuf::UninterpretedOption > uninterpreted_option_; @@ -2332,21 +2792,28 @@ class LIBPROTOBUF_EXPORT MethodOptions : 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 MethodOptions& default_instance(); + void UnsafeArenaSwap(MethodOptions* other); void Swap(MethodOptions* other); // implements Message ---------------------------------------------- - MethodOptions* New() const; + inline MethodOptions* New() const { return New(NULL); } + + MethodOptions* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const MethodOptions& from); @@ -2365,7 +2832,21 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(MethodOptions* other); + protected: + explicit MethodOptions(::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 ---------------------------------------------------- @@ -2399,8 +2880,10 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { ::google::protobuf::internal::ExtensionSet _extensions_; - ::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< ::google::protobuf::UninterpretedOption > uninterpreted_option_; @@ -2427,21 +2910,28 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu } 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 UninterpretedOption_NamePart& default_instance(); + void UnsafeArenaSwap(UninterpretedOption_NamePart* other); void Swap(UninterpretedOption_NamePart* other); // implements Message ---------------------------------------------- - UninterpretedOption_NamePart* New() const; + inline UninterpretedOption_NamePart* New() const { return New(NULL); } + + UninterpretedOption_NamePart* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const UninterpretedOption_NamePart& from); @@ -2460,7 +2950,21 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(UninterpretedOption_NamePart* other); + protected: + explicit UninterpretedOption_NamePart(::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 ---------------------------------------------------- @@ -2478,6 +2982,9 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline ::std::string* mutable_name_part(); inline ::std::string* release_name_part(); inline void set_allocated_name_part(::std::string* name_part); + inline ::std::string* unsafe_arena_release_name_part(); + inline void unsafe_arena_set_allocated_name_part( + ::std::string* name_part); // required bool is_extension = 2; inline bool has_is_extension() const; @@ -2493,11 +3000,16 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline void set_has_is_extension(); inline void clear_has_is_extension(); - ::google::protobuf::UnknownFieldSet _unknown_fields_; + // helper for ByteSize() + int RequiredFieldsByteSizeFallback() const; + ::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_part_; + ::google::protobuf::internal::ArenaStringPtr name_part_; bool is_extension_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2521,21 +3033,28 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : 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 UninterpretedOption& default_instance(); + void UnsafeArenaSwap(UninterpretedOption* other); void Swap(UninterpretedOption* other); // implements Message ---------------------------------------------- - UninterpretedOption* New() const; + inline UninterpretedOption* New() const { return New(NULL); } + + UninterpretedOption* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const UninterpretedOption& from); @@ -2554,7 +3073,21 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(UninterpretedOption* other); + protected: + explicit UninterpretedOption(::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 ---------------------------------------------------- @@ -2586,6 +3119,9 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline ::std::string* mutable_identifier_value(); inline ::std::string* release_identifier_value(); inline void set_allocated_identifier_value(::std::string* identifier_value); + inline ::std::string* unsafe_arena_release_identifier_value(); + inline void unsafe_arena_set_allocated_identifier_value( + ::std::string* identifier_value); // optional uint64 positive_int_value = 4; inline bool has_positive_int_value() const; @@ -2619,6 +3155,9 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline ::std::string* mutable_string_value(); inline ::std::string* release_string_value(); inline void set_allocated_string_value(::std::string* string_value); + inline ::std::string* unsafe_arena_release_string_value(); + inline void unsafe_arena_set_allocated_string_value( + ::std::string* string_value); // optional string aggregate_value = 8; inline bool has_aggregate_value() const; @@ -2631,6 +3170,9 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline ::std::string* mutable_aggregate_value(); inline ::std::string* release_aggregate_value(); inline void set_allocated_aggregate_value(::std::string* aggregate_value); + inline ::std::string* unsafe_arena_release_aggregate_value(); + inline void unsafe_arena_set_allocated_aggregate_value( + ::std::string* aggregate_value); // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) private: @@ -2647,17 +3189,19 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline void set_has_aggregate_value(); inline void clear_has_aggregate_value(); - ::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< ::google::protobuf::UninterpretedOption_NamePart > name_; - ::std::string* identifier_value_; + ::google::protobuf::internal::ArenaStringPtr identifier_value_; ::google::protobuf::uint64 positive_int_value_; ::google::protobuf::int64 negative_int_value_; double double_value_; - ::std::string* string_value_; - ::std::string* aggregate_value_; + ::google::protobuf::internal::ArenaStringPtr string_value_; + ::google::protobuf::internal::ArenaStringPtr aggregate_value_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2680,21 +3224,28 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me } 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 SourceCodeInfo_Location& default_instance(); + void UnsafeArenaSwap(SourceCodeInfo_Location* other); void Swap(SourceCodeInfo_Location* other); // implements Message ---------------------------------------------- - SourceCodeInfo_Location* New() const; + inline SourceCodeInfo_Location* New() const { return New(NULL); } + + SourceCodeInfo_Location* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const SourceCodeInfo_Location& from); @@ -2713,7 +3264,21 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(SourceCodeInfo_Location* other); + protected: + explicit SourceCodeInfo_Location(::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 ---------------------------------------------------- @@ -2755,6 +3320,9 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me inline ::std::string* mutable_leading_comments(); inline ::std::string* release_leading_comments(); inline void set_allocated_leading_comments(::std::string* leading_comments); + inline ::std::string* unsafe_arena_release_leading_comments(); + inline void unsafe_arena_set_allocated_leading_comments( + ::std::string* leading_comments); // optional string trailing_comments = 4; inline bool has_trailing_comments() const; @@ -2767,6 +3335,9 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me inline ::std::string* mutable_trailing_comments(); inline ::std::string* release_trailing_comments(); inline void set_allocated_trailing_comments(::std::string* trailing_comments); + inline ::std::string* unsafe_arena_release_trailing_comments(); + inline void unsafe_arena_set_allocated_trailing_comments( + ::std::string* trailing_comments); // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location) private: @@ -2775,16 +3346,18 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me inline void set_has_trailing_comments(); inline void clear_has_trailing_comments(); - ::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::RepeatedField< ::google::protobuf::int32 > path_; mutable int _path_cached_byte_size_; ::google::protobuf::RepeatedField< ::google::protobuf::int32 > span_; mutable int _span_cached_byte_size_; - ::std::string* leading_comments_; - ::std::string* trailing_comments_; + ::google::protobuf::internal::ArenaStringPtr leading_comments_; + ::google::protobuf::internal::ArenaStringPtr trailing_comments_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2807,21 +3380,28 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : 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 SourceCodeInfo& default_instance(); + void UnsafeArenaSwap(SourceCodeInfo* other); void Swap(SourceCodeInfo* other); // implements Message ---------------------------------------------- - SourceCodeInfo* New() const; + inline SourceCodeInfo* New() const { return New(NULL); } + + SourceCodeInfo* New(::google::protobuf::Arena* arena) const; void CopyFrom(const ::google::protobuf::Message& from); void MergeFrom(const ::google::protobuf::Message& from); void CopyFrom(const SourceCodeInfo& from); @@ -2840,7 +3420,21 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { void SharedCtor(); void SharedDtor(); void SetCachedSize(int size) const; + void InternalSwap(SourceCodeInfo* other); + protected: + explicit SourceCodeInfo(::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 ---------------------------------------------------- @@ -2864,8 +3458,10 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo) private: - ::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< ::google::protobuf::SourceCodeInfo_Location > location_; @@ -2928,68 +3524,67 @@ inline void FileDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void FileDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& FileDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FileDescriptorProto::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.FileDescriptorProto.name) } inline void FileDescriptorProto::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.FileDescriptorProto.name) } -inline void FileDescriptorProto::set_name(const char* value, size_t size) { +inline void FileDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.name) } inline ::std::string* FileDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FileDescriptorProto::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* FileDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FileDescriptorProto::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.FileDescriptorProto.name) +} +inline void FileDescriptorProto::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.FileDescriptorProto.name) } @@ -3004,68 +3599,67 @@ inline void FileDescriptorProto::clear_has_package() { _has_bits_[0] &= ~0x00000002u; } inline void FileDescriptorProto::clear_package() { - if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_->clear(); - } + package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_package(); } inline const ::std::string& FileDescriptorProto::package() const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package) - return *package_; + return package_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FileDescriptorProto::set_package(const ::std::string& value) { set_has_package(); - if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_ = new ::std::string; - } - package_->assign(value); + package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package) } inline void FileDescriptorProto::set_package(const char* value) { set_has_package(); - if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_ = new ::std::string; - } - package_->assign(value); + package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.package) } -inline void FileDescriptorProto::set_package(const char* value, size_t size) { +inline void FileDescriptorProto::set_package(const char* value, + size_t size) { set_has_package(); - if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_ = new ::std::string; - } - package_->assign(reinterpret_cast(value), size); + package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.package) } inline ::std::string* FileDescriptorProto::mutable_package() { set_has_package(); - if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - package_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package) - return package_; + return package_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FileDescriptorProto::release_package() { clear_has_package(); - if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = package_; - package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return package_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileDescriptorProto::unsafe_arena_release_package() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_package(); + return package_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FileDescriptorProto::set_allocated_package(::std::string* package) { - if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete package_; + if (package != NULL) { + set_has_package(); + } else { + clear_has_package(); } - if (package) { + package_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), package, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package) +} +inline void FileDescriptorProto::unsafe_arena_set_allocated_package( + ::std::string* package) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (package != NULL) { set_has_package(); - package_ = package; } else { clear_has_package(); - package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_package(); + package_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + package, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package) } @@ -3323,18 +3917,53 @@ inline const ::google::protobuf::FileOptions& FileDescriptorProto::options() con } inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::FileOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::FileOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options) return options_; } inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::FileOptions* temp = new ::google::protobuf::FileOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::FileOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::FileOptions* FileDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; return temp; } inline void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::FileOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::FileOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -3343,6 +3972,19 @@ inline void FileDescriptorProto::set_allocated_options(::google::protobuf::FileO } // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options) } +inline void FileDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::FileOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.options) +} // optional .google.protobuf.SourceCodeInfo source_code_info = 9; inline bool FileDescriptorProto::has_source_code_info() const { @@ -3364,18 +4006,53 @@ inline const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_cod } inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() { set_has_source_code_info(); - if (source_code_info_ == NULL) source_code_info_ = new ::google::protobuf::SourceCodeInfo; + if (source_code_info_ == NULL) { + source_code_info_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::SourceCodeInfo >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info) return source_code_info_; } inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + clear_has_source_code_info(); + if (GetArenaNoVirtual() != NULL) { + if (source_code_info_ == NULL) { + return NULL; + } else { + ::google::protobuf::SourceCodeInfo* temp = new ::google::protobuf::SourceCodeInfo; + temp->MergeFrom(*source_code_info_); + source_code_info_ = NULL; + return temp; + } + } else { + ::google::protobuf::SourceCodeInfo* temp = source_code_info_; + source_code_info_ = NULL; + return temp; + } +} +inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::unsafe_arena_release_source_code_info() { clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; return temp; } inline void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) { - delete source_code_info_; + if (GetArenaNoVirtual() == NULL) { + delete source_code_info_; + } + if (source_code_info != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(source_code_info) == NULL) { + GetArenaNoVirtual()->Own(source_code_info); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(source_code_info)) { + ::google::protobuf::SourceCodeInfo* new_source_code_info = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::SourceCodeInfo >( + GetArenaNoVirtual()); + new_source_code_info->CopyFrom(*source_code_info); + source_code_info = new_source_code_info; + } + } source_code_info_ = source_code_info; if (source_code_info) { set_has_source_code_info(); @@ -3384,6 +4061,94 @@ inline void FileDescriptorProto::set_allocated_source_code_info(::google::protob } // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.source_code_info) } +inline void FileDescriptorProto::unsafe_arena_set_allocated_source_code_info( + ::google::protobuf::SourceCodeInfo* source_code_info) { + if (GetArenaNoVirtual() == NULL) { + delete source_code_info_; + } + source_code_info_ = source_code_info; + if (source_code_info) { + set_has_source_code_info(); + } else { + clear_has_source_code_info(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.source_code_info) +} + +// optional string syntax = 12; +inline bool FileDescriptorProto::has_syntax() const { + return (_has_bits_[0] & 0x00000800u) != 0; +} +inline void FileDescriptorProto::set_has_syntax() { + _has_bits_[0] |= 0x00000800u; +} +inline void FileDescriptorProto::clear_has_syntax() { + _has_bits_[0] &= ~0x00000800u; +} +inline void FileDescriptorProto::clear_syntax() { + syntax_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); + clear_has_syntax(); +} +inline const ::std::string& FileDescriptorProto::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax) + return syntax_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void FileDescriptorProto::set_syntax(const ::std::string& value) { + set_has_syntax(); + syntax_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax) +} +inline void FileDescriptorProto::set_syntax(const char* value) { + set_has_syntax(); + syntax_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.syntax) +} +inline void FileDescriptorProto::set_syntax(const char* value, + size_t size) { + set_has_syntax(); + syntax_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.syntax) +} +inline ::std::string* FileDescriptorProto::mutable_syntax() { + set_has_syntax(); + // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax) + return syntax_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileDescriptorProto::release_syntax() { + clear_has_syntax(); + return syntax_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileDescriptorProto::unsafe_arena_release_syntax() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_syntax(); + return syntax_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); +} +inline void FileDescriptorProto::set_allocated_syntax(::std::string* syntax) { + if (syntax != NULL) { + set_has_syntax(); + } else { + clear_has_syntax(); + } + syntax_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), syntax, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax) +} +inline void FileDescriptorProto::unsafe_arena_set_allocated_syntax( + ::std::string* syntax) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (syntax != NULL) { + set_has_syntax(); + } else { + clear_has_syntax(); + } + set_has_syntax(); + syntax_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + syntax, GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax) +} // ------------------------------------------------------------------- @@ -3452,68 +4217,67 @@ inline void DescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void DescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& DescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void DescriptorProto::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.DescriptorProto.name) } inline void DescriptorProto::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.DescriptorProto.name) } -inline void DescriptorProto::set_name(const char* value, size_t size) { +inline void DescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.name) } inline ::std::string* DescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* DescriptorProto::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* DescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void DescriptorProto::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.DescriptorProto.name) +} +inline void DescriptorProto::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.DescriptorProto.name) } @@ -3717,18 +4481,53 @@ inline const ::google::protobuf::MessageOptions& DescriptorProto::options() cons } inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::MessageOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options) return options_; } inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::MessageOptions* temp = new ::google::protobuf::MessageOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::MessageOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::MessageOptions* DescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; return temp; } inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::MessageOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::MessageOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -3737,6 +4536,19 @@ inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOp } // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options) } +inline void DescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::MessageOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.DescriptorProto.options) +} // ------------------------------------------------------------------- @@ -3753,68 +4565,67 @@ inline void FieldDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void FieldDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& FieldDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FieldDescriptorProto::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.FieldDescriptorProto.name) } inline void FieldDescriptorProto::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.FieldDescriptorProto.name) } -inline void FieldDescriptorProto::set_name(const char* value, size_t size) { +inline void FieldDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.name) } inline ::std::string* FieldDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FieldDescriptorProto::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* FieldDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FieldDescriptorProto::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.FieldDescriptorProto.name) +} +inline void FieldDescriptorProto::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.FieldDescriptorProto.name) } @@ -3903,68 +4714,67 @@ inline void FieldDescriptorProto::clear_has_type_name() { _has_bits_[0] &= ~0x00000010u; } inline void FieldDescriptorProto::clear_type_name() { - if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_->clear(); - } + type_name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_type_name(); } inline const ::std::string& FieldDescriptorProto::type_name() const { // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name) - return *type_name_; + return type_name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FieldDescriptorProto::set_type_name(const ::std::string& value) { set_has_type_name(); - if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_ = new ::std::string; - } - type_name_->assign(value); + type_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name) } inline void FieldDescriptorProto::set_type_name(const char* value) { set_has_type_name(); - if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_ = new ::std::string; - } - type_name_->assign(value); + type_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.type_name) } -inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) { +inline void FieldDescriptorProto::set_type_name(const char* value, + size_t size) { set_has_type_name(); - if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_ = new ::std::string; - } - type_name_->assign(reinterpret_cast(value), size); + type_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.type_name) } inline ::std::string* FieldDescriptorProto::mutable_type_name() { set_has_type_name(); - if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - type_name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name) - return type_name_; + return type_name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FieldDescriptorProto::release_type_name() { clear_has_type_name(); - if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = type_name_; - type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return type_name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FieldDescriptorProto::unsafe_arena_release_type_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_type_name(); + return type_name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) { - if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete type_name_; + if (type_name != NULL) { + set_has_type_name(); + } else { + clear_has_type_name(); } - if (type_name) { + type_name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_name, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name) +} +inline void FieldDescriptorProto::unsafe_arena_set_allocated_type_name( + ::std::string* type_name) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (type_name != NULL) { set_has_type_name(); - type_name_ = type_name; } else { clear_has_type_name(); - type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_type_name(); + type_name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + type_name, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name) } @@ -3979,68 +4789,67 @@ inline void FieldDescriptorProto::clear_has_extendee() { _has_bits_[0] &= ~0x00000020u; } inline void FieldDescriptorProto::clear_extendee() { - if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_->clear(); - } + extendee_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_extendee(); } inline const ::std::string& FieldDescriptorProto::extendee() const { // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee) - return *extendee_; + return extendee_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FieldDescriptorProto::set_extendee(const ::std::string& value) { set_has_extendee(); - if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_ = new ::std::string; - } - extendee_->assign(value); + extendee_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee) } inline void FieldDescriptorProto::set_extendee(const char* value) { set_has_extendee(); - if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_ = new ::std::string; - } - extendee_->assign(value); + extendee_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.extendee) } -inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) { +inline void FieldDescriptorProto::set_extendee(const char* value, + size_t size) { set_has_extendee(); - if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_ = new ::std::string; - } - extendee_->assign(reinterpret_cast(value), size); + extendee_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.extendee) } inline ::std::string* FieldDescriptorProto::mutable_extendee() { set_has_extendee(); - if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - extendee_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee) - return extendee_; + return extendee_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FieldDescriptorProto::release_extendee() { clear_has_extendee(); - if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = extendee_; - extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return extendee_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FieldDescriptorProto::unsafe_arena_release_extendee() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_extendee(); + return extendee_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) { - if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete extendee_; + if (extendee != NULL) { + set_has_extendee(); + } else { + clear_has_extendee(); } - if (extendee) { + extendee_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extendee, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee) +} +inline void FieldDescriptorProto::unsafe_arena_set_allocated_extendee( + ::std::string* extendee) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (extendee != NULL) { set_has_extendee(); - extendee_ = extendee; } else { clear_has_extendee(); - extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_extendee(); + extendee_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + extendee, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee) } @@ -4055,68 +4864,67 @@ inline void FieldDescriptorProto::clear_has_default_value() { _has_bits_[0] &= ~0x00000040u; } inline void FieldDescriptorProto::clear_default_value() { - if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_->clear(); - } + default_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_default_value(); } inline const ::std::string& FieldDescriptorProto::default_value() const { // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value) - return *default_value_; + return default_value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FieldDescriptorProto::set_default_value(const ::std::string& value) { set_has_default_value(); - if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_ = new ::std::string; - } - default_value_->assign(value); + default_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value) } inline void FieldDescriptorProto::set_default_value(const char* value) { set_has_default_value(); - if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_ = new ::std::string; - } - default_value_->assign(value); + default_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.default_value) } -inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) { +inline void FieldDescriptorProto::set_default_value(const char* value, + size_t size) { set_has_default_value(); - if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_ = new ::std::string; - } - default_value_->assign(reinterpret_cast(value), size); + default_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.default_value) } inline ::std::string* FieldDescriptorProto::mutable_default_value() { set_has_default_value(); - if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - default_value_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value) - return default_value_; + return default_value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FieldDescriptorProto::release_default_value() { clear_has_default_value(); - if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = default_value_; - default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return default_value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FieldDescriptorProto::unsafe_arena_release_default_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_default_value(); + return default_value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) { - if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete default_value_; + if (default_value != NULL) { + set_has_default_value(); + } else { + clear_has_default_value(); } - if (default_value) { + default_value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value) +} +inline void FieldDescriptorProto::unsafe_arena_set_allocated_default_value( + ::std::string* default_value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (default_value != NULL) { set_has_default_value(); - default_value_ = default_value; } else { clear_has_default_value(); - default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_default_value(); + default_value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + default_value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value) } @@ -4164,18 +4972,53 @@ inline const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() c } inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::FieldOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options) return options_; } inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::FieldOptions* temp = new ::google::protobuf::FieldOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::FieldOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::FieldOptions* FieldDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; return temp; } inline void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::FieldOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::FieldOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -4184,6 +5027,19 @@ inline void FieldDescriptorProto::set_allocated_options(::google::protobuf::Fiel } // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options) } +inline void FieldDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::FieldOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FieldDescriptorProto.options) +} // ------------------------------------------------------------------- @@ -4200,68 +5056,67 @@ inline void OneofDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void OneofDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& OneofDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void OneofDescriptorProto::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.OneofDescriptorProto.name) } inline void OneofDescriptorProto::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.OneofDescriptorProto.name) } -inline void OneofDescriptorProto::set_name(const char* value, size_t size) { +inline void OneofDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.OneofDescriptorProto.name) } inline ::std::string* OneofDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* OneofDescriptorProto::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* OneofDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void OneofDescriptorProto::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.OneofDescriptorProto.name) +} +inline void OneofDescriptorProto::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.OneofDescriptorProto.name) } @@ -4280,68 +5135,67 @@ inline void EnumDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void EnumDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& EnumDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void EnumDescriptorProto::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.EnumDescriptorProto.name) } inline void EnumDescriptorProto::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.EnumDescriptorProto.name) } -inline void EnumDescriptorProto::set_name(const char* value, size_t size) { +inline void EnumDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.name) } inline ::std::string* EnumDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* EnumDescriptorProto::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* EnumDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void EnumDescriptorProto::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.EnumDescriptorProto.name) +} +inline void EnumDescriptorProto::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.EnumDescriptorProto.name) } @@ -4395,18 +5249,53 @@ inline const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() con } inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::EnumOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options) return options_; } inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::EnumOptions* temp = new ::google::protobuf::EnumOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::EnumOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::EnumOptions* EnumDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; return temp; } inline void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::EnumOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::EnumOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -4415,6 +5304,19 @@ inline void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumO } // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options) } +inline void EnumDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::EnumOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumDescriptorProto.options) +} // ------------------------------------------------------------------- @@ -4431,68 +5333,67 @@ inline void EnumValueDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void EnumValueDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& EnumValueDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void EnumValueDescriptorProto::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.EnumValueDescriptorProto.name) } inline void EnumValueDescriptorProto::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.EnumValueDescriptorProto.name) } -inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) { +inline void EnumValueDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValueDescriptorProto.name) } inline ::std::string* EnumValueDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* EnumValueDescriptorProto::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* EnumValueDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void EnumValueDescriptorProto::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.EnumValueDescriptorProto.name) +} +inline void EnumValueDescriptorProto::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.EnumValueDescriptorProto.name) } @@ -4540,18 +5441,53 @@ inline const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::opt } inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::EnumValueOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options) return options_; } inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::EnumValueOptions* temp = new ::google::protobuf::EnumValueOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::EnumValueOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; return temp; } inline void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::EnumValueOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::EnumValueOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -4560,6 +5496,19 @@ inline void EnumValueDescriptorProto::set_allocated_options(::google::protobuf:: } // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options) } +inline void EnumValueDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::EnumValueOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumValueDescriptorProto.options) +} // ------------------------------------------------------------------- @@ -4576,68 +5525,67 @@ inline void ServiceDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void ServiceDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& ServiceDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void ServiceDescriptorProto::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.ServiceDescriptorProto.name) } inline void ServiceDescriptorProto::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.ServiceDescriptorProto.name) } -inline void ServiceDescriptorProto::set_name(const char* value, size_t size) { +inline void ServiceDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.ServiceDescriptorProto.name) } inline ::std::string* ServiceDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* ServiceDescriptorProto::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* ServiceDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void ServiceDescriptorProto::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.ServiceDescriptorProto.name) +} +inline void ServiceDescriptorProto::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.ServiceDescriptorProto.name) } @@ -4691,18 +5639,53 @@ inline const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options } inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::ServiceOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options) return options_; } inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::ServiceOptions* temp = new ::google::protobuf::ServiceOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::ServiceOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; return temp; } inline void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::ServiceOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::ServiceOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -4711,6 +5694,19 @@ inline void ServiceDescriptorProto::set_allocated_options(::google::protobuf::Se } // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options) } +inline void ServiceDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::ServiceOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.ServiceDescriptorProto.options) +} // ------------------------------------------------------------------- @@ -4727,68 +5723,67 @@ inline void MethodDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } inline void MethodDescriptorProto::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } + name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name(); } inline const ::std::string& MethodDescriptorProto::name() const { // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name) - return *name_; + return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void MethodDescriptorProto::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.MethodDescriptorProto.name) } inline void MethodDescriptorProto::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.MethodDescriptorProto.name) } -inline void MethodDescriptorProto::set_name(const char* value, size_t size) { +inline void MethodDescriptorProto::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(value), size); + name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.name) } inline ::std::string* MethodDescriptorProto::mutable_name() { set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name) - return name_; + return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* MethodDescriptorProto::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* MethodDescriptorProto::unsafe_arena_release_name() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name(); + return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void MethodDescriptorProto::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.MethodDescriptorProto.name) +} +inline void MethodDescriptorProto::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.MethodDescriptorProto.name) } @@ -4803,68 +5798,67 @@ inline void MethodDescriptorProto::clear_has_input_type() { _has_bits_[0] &= ~0x00000002u; } inline void MethodDescriptorProto::clear_input_type() { - if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_->clear(); - } + input_type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_input_type(); } inline const ::std::string& MethodDescriptorProto::input_type() const { // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type) - return *input_type_; + return input_type_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void MethodDescriptorProto::set_input_type(const ::std::string& value) { set_has_input_type(); - if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_ = new ::std::string; - } - input_type_->assign(value); + input_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type) } inline void MethodDescriptorProto::set_input_type(const char* value) { set_has_input_type(); - if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_ = new ::std::string; - } - input_type_->assign(value); + input_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.input_type) } -inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) { +inline void MethodDescriptorProto::set_input_type(const char* value, + size_t size) { set_has_input_type(); - if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_ = new ::std::string; - } - input_type_->assign(reinterpret_cast(value), size); + input_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.input_type) } inline ::std::string* MethodDescriptorProto::mutable_input_type() { set_has_input_type(); - if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - input_type_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type) - return input_type_; + return input_type_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* MethodDescriptorProto::release_input_type() { clear_has_input_type(); - if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = input_type_; - input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return input_type_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* MethodDescriptorProto::unsafe_arena_release_input_type() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_input_type(); + return input_type_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) { - if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete input_type_; + if (input_type != NULL) { + set_has_input_type(); + } else { + clear_has_input_type(); } - if (input_type) { + input_type_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), input_type, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type) +} +inline void MethodDescriptorProto::unsafe_arena_set_allocated_input_type( + ::std::string* input_type) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (input_type != NULL) { set_has_input_type(); - input_type_ = input_type; } else { clear_has_input_type(); - input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_input_type(); + input_type_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + input_type, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type) } @@ -4879,68 +5873,67 @@ inline void MethodDescriptorProto::clear_has_output_type() { _has_bits_[0] &= ~0x00000004u; } inline void MethodDescriptorProto::clear_output_type() { - if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_->clear(); - } + output_type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_output_type(); } inline const ::std::string& MethodDescriptorProto::output_type() const { // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type) - return *output_type_; + return output_type_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void MethodDescriptorProto::set_output_type(const ::std::string& value) { set_has_output_type(); - if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_ = new ::std::string; - } - output_type_->assign(value); + output_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type) } inline void MethodDescriptorProto::set_output_type(const char* value) { set_has_output_type(); - if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_ = new ::std::string; - } - output_type_->assign(value); + output_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.output_type) } -inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) { +inline void MethodDescriptorProto::set_output_type(const char* value, + size_t size) { set_has_output_type(); - if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_ = new ::std::string; - } - output_type_->assign(reinterpret_cast(value), size); + output_type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.output_type) } inline ::std::string* MethodDescriptorProto::mutable_output_type() { set_has_output_type(); - if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - output_type_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type) - return output_type_; + return output_type_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* MethodDescriptorProto::release_output_type() { clear_has_output_type(); - if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = output_type_; - output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return output_type_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* MethodDescriptorProto::unsafe_arena_release_output_type() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_output_type(); + return output_type_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) { - if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete output_type_; + if (output_type != NULL) { + set_has_output_type(); + } else { + clear_has_output_type(); } - if (output_type) { + output_type_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), output_type, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type) +} +inline void MethodDescriptorProto::unsafe_arena_set_allocated_output_type( + ::std::string* output_type) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (output_type != NULL) { set_has_output_type(); - output_type_ = output_type; } else { clear_has_output_type(); - output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_output_type(); + output_type_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + output_type, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type) } @@ -4964,18 +5957,53 @@ inline const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() } inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { set_has_options(); - if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions; + if (options_ == NULL) { + options_ = ::google::protobuf::Arena::CreateMessage< ::google::protobuf::MethodOptions >( + GetArenaNoVirtual()); + } // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options) return options_; } inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + clear_has_options(); + if (GetArenaNoVirtual() != NULL) { + if (options_ == NULL) { + return NULL; + } else { + ::google::protobuf::MethodOptions* temp = new ::google::protobuf::MethodOptions; + temp->MergeFrom(*options_); + options_ = NULL; + return temp; + } + } else { + ::google::protobuf::MethodOptions* temp = options_; + options_ = NULL; + return temp; + } +} +inline ::google::protobuf::MethodOptions* MethodDescriptorProto::unsafe_arena_release_options() { clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; return temp; } inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) { - delete options_; + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + if (options != NULL) { + if (GetArenaNoVirtual() != NULL && + ::google::protobuf::Arena::GetArena(options) == NULL) { + GetArenaNoVirtual()->Own(options); + } else if (GetArenaNoVirtual() != + ::google::protobuf::Arena::GetArena(options)) { + ::google::protobuf::MethodOptions* new_options = + ::google::protobuf::Arena::CreateMessage< ::google::protobuf::MethodOptions >( + GetArenaNoVirtual()); + new_options->CopyFrom(*options); + options = new_options; + } + } options_ = options; if (options) { set_has_options(); @@ -4984,6 +6012,19 @@ inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::Met } // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options) } +inline void MethodDescriptorProto::unsafe_arena_set_allocated_options( + ::google::protobuf::MethodOptions* options) { + if (GetArenaNoVirtual() == NULL) { + delete options_; + } + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.MethodDescriptorProto.options) +} // ------------------------------------------------------------------- @@ -5000,68 +6041,67 @@ inline void FileOptions::clear_has_java_package() { _has_bits_[0] &= ~0x00000001u; } inline void FileOptions::clear_java_package() { - if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_->clear(); - } + java_package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_java_package(); } inline const ::std::string& FileOptions::java_package() const { // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package) - return *java_package_; + return java_package_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FileOptions::set_java_package(const ::std::string& value) { set_has_java_package(); - if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_ = new ::std::string; - } - java_package_->assign(value); + java_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package) } inline void FileOptions::set_java_package(const char* value) { set_has_java_package(); - if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_ = new ::std::string; - } - java_package_->assign(value); + java_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_package) } -inline void FileOptions::set_java_package(const char* value, size_t size) { +inline void FileOptions::set_java_package(const char* value, + size_t size) { set_has_java_package(); - if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_ = new ::std::string; - } - java_package_->assign(reinterpret_cast(value), size); + java_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_package) } inline ::std::string* FileOptions::mutable_java_package() { set_has_java_package(); - if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_package_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package) - return java_package_; + return java_package_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FileOptions::release_java_package() { clear_has_java_package(); - if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = java_package_; - java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return java_package_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileOptions::unsafe_arena_release_java_package() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_java_package(); + return java_package_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FileOptions::set_allocated_java_package(::std::string* java_package) { - if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete java_package_; + if (java_package != NULL) { + set_has_java_package(); + } else { + clear_has_java_package(); } - if (java_package) { + java_package_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_package, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package) +} +inline void FileOptions::unsafe_arena_set_allocated_java_package( + ::std::string* java_package) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (java_package != NULL) { set_has_java_package(); - java_package_ = java_package; } else { clear_has_java_package(); - java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_java_package(); + java_package_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + java_package, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package) } @@ -5076,68 +6116,67 @@ inline void FileOptions::clear_has_java_outer_classname() { _has_bits_[0] &= ~0x00000002u; } inline void FileOptions::clear_java_outer_classname() { - if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_->clear(); - } + java_outer_classname_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_java_outer_classname(); } inline const ::std::string& FileOptions::java_outer_classname() const { // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname) - return *java_outer_classname_; + return java_outer_classname_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FileOptions::set_java_outer_classname(const ::std::string& value) { set_has_java_outer_classname(); - if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_ = new ::std::string; - } - java_outer_classname_->assign(value); + java_outer_classname_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname) } inline void FileOptions::set_java_outer_classname(const char* value) { set_has_java_outer_classname(); - if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_ = new ::std::string; - } - java_outer_classname_->assign(value); + java_outer_classname_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_outer_classname) } -inline void FileOptions::set_java_outer_classname(const char* value, size_t size) { +inline void FileOptions::set_java_outer_classname(const char* value, + size_t size) { set_has_java_outer_classname(); - if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_ = new ::std::string; - } - java_outer_classname_->assign(reinterpret_cast(value), size); + java_outer_classname_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_outer_classname) } inline ::std::string* FileOptions::mutable_java_outer_classname() { set_has_java_outer_classname(); - if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - java_outer_classname_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname) - return java_outer_classname_; + return java_outer_classname_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FileOptions::release_java_outer_classname() { clear_has_java_outer_classname(); - if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = java_outer_classname_; - java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return java_outer_classname_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileOptions::unsafe_arena_release_java_outer_classname() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_java_outer_classname(); + return java_outer_classname_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) { - if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete java_outer_classname_; + if (java_outer_classname != NULL) { + set_has_java_outer_classname(); + } else { + clear_has_java_outer_classname(); } - if (java_outer_classname) { + java_outer_classname_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_outer_classname, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname) +} +inline void FileOptions::unsafe_arena_set_allocated_java_outer_classname( + ::std::string* java_outer_classname) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (java_outer_classname != NULL) { set_has_java_outer_classname(); - java_outer_classname_ = java_outer_classname; } else { clear_has_java_outer_classname(); - java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_java_outer_classname(); + java_outer_classname_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + java_outer_classname, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname) } @@ -5249,68 +6288,67 @@ inline void FileOptions::clear_has_go_package() { _has_bits_[0] &= ~0x00000040u; } inline void FileOptions::clear_go_package() { - if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_->clear(); - } + go_package_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_go_package(); } inline const ::std::string& FileOptions::go_package() const { // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package) - return *go_package_; + return go_package_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void FileOptions::set_go_package(const ::std::string& value) { set_has_go_package(); - if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_ = new ::std::string; - } - go_package_->assign(value); + go_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package) } inline void FileOptions::set_go_package(const char* value) { set_has_go_package(); - if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_ = new ::std::string; - } - go_package_->assign(value); + go_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.go_package) } -inline void FileOptions::set_go_package(const char* value, size_t size) { +inline void FileOptions::set_go_package(const char* value, + size_t size) { set_has_go_package(); - if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_ = new ::std::string; - } - go_package_->assign(reinterpret_cast(value), size); + go_package_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.go_package) } inline ::std::string* FileOptions::mutable_go_package() { set_has_go_package(); - if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - go_package_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package) - return go_package_; + return go_package_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* FileOptions::release_go_package() { clear_has_go_package(); - if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = go_package_; - go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return go_package_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* FileOptions::unsafe_arena_release_go_package() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_go_package(); + return go_package_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void FileOptions::set_allocated_go_package(::std::string* go_package) { - if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete go_package_; + if (go_package != NULL) { + set_has_go_package(); + } else { + clear_has_go_package(); } - if (go_package) { + go_package_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), go_package, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package) +} +inline void FileOptions::unsafe_arena_set_allocated_go_package( + ::std::string* go_package) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (go_package != NULL) { set_has_go_package(); - go_package_ = go_package; } else { clear_has_go_package(); - go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_go_package(); + go_package_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + go_package, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package) } @@ -5516,6 +6554,30 @@ inline void MessageOptions::set_deprecated(bool value) { // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated) } +// optional bool map_entry = 7; +inline bool MessageOptions::has_map_entry() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void MessageOptions::set_has_map_entry() { + _has_bits_[0] |= 0x00000008u; +} +inline void MessageOptions::clear_has_map_entry() { + _has_bits_[0] &= ~0x00000008u; +} +inline void MessageOptions::clear_map_entry() { + map_entry_ = false; + clear_has_map_entry(); +} +inline bool MessageOptions::map_entry() const { + // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry) + return map_entry_; +} +inline void MessageOptions::set_map_entry(bool value) { + set_has_map_entry(); + map_entry_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.map_entry) +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int MessageOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -5647,91 +6709,15 @@ inline void FieldOptions::set_deprecated(bool value) { // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated) } -// optional string experimental_map_key = 9; -inline bool FieldOptions::has_experimental_map_key() const { - return (_has_bits_[0] & 0x00000010u) != 0; -} -inline void FieldOptions::set_has_experimental_map_key() { - _has_bits_[0] |= 0x00000010u; -} -inline void FieldOptions::clear_has_experimental_map_key() { - _has_bits_[0] &= ~0x00000010u; -} -inline void FieldOptions::clear_experimental_map_key() { - if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_->clear(); - } - clear_has_experimental_map_key(); -} -inline const ::std::string& FieldOptions::experimental_map_key() const { - // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.experimental_map_key) - return *experimental_map_key_; -} -inline void FieldOptions::set_experimental_map_key(const ::std::string& value) { - set_has_experimental_map_key(); - if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_ = new ::std::string; - } - experimental_map_key_->assign(value); - // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.experimental_map_key) -} -inline void FieldOptions::set_experimental_map_key(const char* value) { - set_has_experimental_map_key(); - if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_ = new ::std::string; - } - experimental_map_key_->assign(value); - // @@protoc_insertion_point(field_set_char:google.protobuf.FieldOptions.experimental_map_key) -} -inline void FieldOptions::set_experimental_map_key(const char* value, size_t size) { - set_has_experimental_map_key(); - if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_ = new ::std::string; - } - experimental_map_key_->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldOptions.experimental_map_key) -} -inline ::std::string* FieldOptions::mutable_experimental_map_key() { - set_has_experimental_map_key(); - if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - experimental_map_key_ = new ::std::string; - } - // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.experimental_map_key) - return experimental_map_key_; -} -inline ::std::string* FieldOptions::release_experimental_map_key() { - clear_has_experimental_map_key(); - if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = experimental_map_key_; - experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } -} -inline void FieldOptions::set_allocated_experimental_map_key(::std::string* experimental_map_key) { - if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete experimental_map_key_; - } - if (experimental_map_key) { - set_has_experimental_map_key(); - experimental_map_key_ = experimental_map_key; - } else { - clear_has_experimental_map_key(); - experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - } - // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldOptions.experimental_map_key) -} - // optional bool weak = 10 [default = false]; inline bool FieldOptions::has_weak() const { - return (_has_bits_[0] & 0x00000020u) != 0; + return (_has_bits_[0] & 0x00000010u) != 0; } inline void FieldOptions::set_has_weak() { - _has_bits_[0] |= 0x00000020u; + _has_bits_[0] |= 0x00000010u; } inline void FieldOptions::clear_has_weak() { - _has_bits_[0] &= ~0x00000020u; + _has_bits_[0] &= ~0x00000010u; } inline void FieldOptions::clear_weak() { weak_ = false; @@ -6048,68 +7034,67 @@ inline void UninterpretedOption_NamePart::clear_has_name_part() { _has_bits_[0] &= ~0x00000001u; } inline void UninterpretedOption_NamePart::clear_name_part() { - if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_->clear(); - } + name_part_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_name_part(); } inline const ::std::string& UninterpretedOption_NamePart::name_part() const { // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part) - return *name_part_; + return name_part_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) { set_has_name_part(); - if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_ = new ::std::string; - } - name_part_->assign(value); + name_part_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part) } inline void UninterpretedOption_NamePart::set_name_part(const char* value) { set_has_name_part(); - if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_ = new ::std::string; - } - name_part_->assign(value); + name_part_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.NamePart.name_part) } -inline void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) { +inline void UninterpretedOption_NamePart::set_name_part(const char* value, + size_t size) { set_has_name_part(); - if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_ = new ::std::string; - } - name_part_->assign(reinterpret_cast(value), size); + name_part_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.NamePart.name_part) } inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { set_has_name_part(); - if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_part_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part) - return name_part_; + return name_part_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* UninterpretedOption_NamePart::release_name_part() { clear_has_name_part(); - if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = name_part_; - name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return name_part_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* UninterpretedOption_NamePart::unsafe_arena_release_name_part() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_name_part(); + return name_part_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) { - if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_part_; + if (name_part != NULL) { + set_has_name_part(); + } else { + clear_has_name_part(); } - if (name_part) { + name_part_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name_part, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part) +} +inline void UninterpretedOption_NamePart::unsafe_arena_set_allocated_name_part( + ::std::string* name_part) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (name_part != NULL) { set_has_name_part(); - name_part_ = name_part; } else { clear_has_name_part(); - name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_name_part(); + name_part_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + name_part, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part) } @@ -6182,68 +7167,67 @@ inline void UninterpretedOption::clear_has_identifier_value() { _has_bits_[0] &= ~0x00000002u; } inline void UninterpretedOption::clear_identifier_value() { - if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_->clear(); - } + identifier_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_identifier_value(); } inline const ::std::string& UninterpretedOption::identifier_value() const { // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value) - return *identifier_value_; + return identifier_value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void UninterpretedOption::set_identifier_value(const ::std::string& value) { set_has_identifier_value(); - if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_ = new ::std::string; - } - identifier_value_->assign(value); + identifier_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value) } inline void UninterpretedOption::set_identifier_value(const char* value) { set_has_identifier_value(); - if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_ = new ::std::string; - } - identifier_value_->assign(value); + identifier_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.identifier_value) } -inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) { +inline void UninterpretedOption::set_identifier_value(const char* value, + size_t size) { set_has_identifier_value(); - if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_ = new ::std::string; - } - identifier_value_->assign(reinterpret_cast(value), size); + identifier_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.identifier_value) } inline ::std::string* UninterpretedOption::mutable_identifier_value() { set_has_identifier_value(); - if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - identifier_value_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value) - return identifier_value_; + return identifier_value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* UninterpretedOption::release_identifier_value() { clear_has_identifier_value(); - if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = identifier_value_; - identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return identifier_value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* UninterpretedOption::unsafe_arena_release_identifier_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_identifier_value(); + return identifier_value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) { - if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete identifier_value_; + if (identifier_value != NULL) { + set_has_identifier_value(); + } else { + clear_has_identifier_value(); } - if (identifier_value) { + identifier_value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), identifier_value, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value) +} +inline void UninterpretedOption::unsafe_arena_set_allocated_identifier_value( + ::std::string* identifier_value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (identifier_value != NULL) { set_has_identifier_value(); - identifier_value_ = identifier_value; } else { clear_has_identifier_value(); - identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_identifier_value(); + identifier_value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + identifier_value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value) } @@ -6330,68 +7314,67 @@ inline void UninterpretedOption::clear_has_string_value() { _has_bits_[0] &= ~0x00000020u; } inline void UninterpretedOption::clear_string_value() { - if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_->clear(); - } + string_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_string_value(); } inline const ::std::string& UninterpretedOption::string_value() const { // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value) - return *string_value_; + return string_value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void UninterpretedOption::set_string_value(const ::std::string& value) { set_has_string_value(); - if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_ = new ::std::string; - } - string_value_->assign(value); + string_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value) } inline void UninterpretedOption::set_string_value(const char* value) { set_has_string_value(); - if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_ = new ::std::string; - } - string_value_->assign(value); + string_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.string_value) } -inline void UninterpretedOption::set_string_value(const void* value, size_t size) { +inline void UninterpretedOption::set_string_value(const void* value, + size_t size) { set_has_string_value(); - if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_ = new ::std::string; - } - string_value_->assign(reinterpret_cast(value), size); + string_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.string_value) } inline ::std::string* UninterpretedOption::mutable_string_value() { set_has_string_value(); - if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - string_value_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value) - return string_value_; + return string_value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* UninterpretedOption::release_string_value() { clear_has_string_value(); - if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = string_value_; - string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return string_value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* UninterpretedOption::unsafe_arena_release_string_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_string_value(); + return string_value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void UninterpretedOption::set_allocated_string_value(::std::string* string_value) { - if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete string_value_; + if (string_value != NULL) { + set_has_string_value(); + } else { + clear_has_string_value(); } - if (string_value) { + string_value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), string_value, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value) +} +inline void UninterpretedOption::unsafe_arena_set_allocated_string_value( + ::std::string* string_value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (string_value != NULL) { set_has_string_value(); - string_value_ = string_value; } else { clear_has_string_value(); - string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_string_value(); + string_value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + string_value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value) } @@ -6406,68 +7389,67 @@ inline void UninterpretedOption::clear_has_aggregate_value() { _has_bits_[0] &= ~0x00000040u; } inline void UninterpretedOption::clear_aggregate_value() { - if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_->clear(); - } + aggregate_value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_aggregate_value(); } inline const ::std::string& UninterpretedOption::aggregate_value() const { // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value) - return *aggregate_value_; + return aggregate_value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void UninterpretedOption::set_aggregate_value(const ::std::string& value) { set_has_aggregate_value(); - if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_ = new ::std::string; - } - aggregate_value_->assign(value); + aggregate_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value) } inline void UninterpretedOption::set_aggregate_value(const char* value) { set_has_aggregate_value(); - if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_ = new ::std::string; - } - aggregate_value_->assign(value); + aggregate_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.aggregate_value) } -inline void UninterpretedOption::set_aggregate_value(const char* value, size_t size) { +inline void UninterpretedOption::set_aggregate_value(const char* value, + size_t size) { set_has_aggregate_value(); - if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_ = new ::std::string; - } - aggregate_value_->assign(reinterpret_cast(value), size); + aggregate_value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.aggregate_value) } inline ::std::string* UninterpretedOption::mutable_aggregate_value() { set_has_aggregate_value(); - if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - aggregate_value_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value) - return aggregate_value_; + return aggregate_value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* UninterpretedOption::release_aggregate_value() { clear_has_aggregate_value(); - if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = aggregate_value_; - aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return aggregate_value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* UninterpretedOption::unsafe_arena_release_aggregate_value() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_aggregate_value(); + return aggregate_value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) { - if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete aggregate_value_; + if (aggregate_value != NULL) { + set_has_aggregate_value(); + } else { + clear_has_aggregate_value(); } - if (aggregate_value) { + aggregate_value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), aggregate_value, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value) +} +inline void UninterpretedOption::unsafe_arena_set_allocated_aggregate_value( + ::std::string* aggregate_value) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (aggregate_value != NULL) { set_has_aggregate_value(); - aggregate_value_ = aggregate_value; } else { clear_has_aggregate_value(); - aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_aggregate_value(); + aggregate_value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + aggregate_value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value) } @@ -6546,68 +7528,67 @@ inline void SourceCodeInfo_Location::clear_has_leading_comments() { _has_bits_[0] &= ~0x00000004u; } inline void SourceCodeInfo_Location::clear_leading_comments() { - if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_->clear(); - } + leading_comments_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_leading_comments(); } inline const ::std::string& SourceCodeInfo_Location::leading_comments() const { // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments) - return *leading_comments_; + return leading_comments_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) { set_has_leading_comments(); - if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_ = new ::std::string; - } - leading_comments_->assign(value); + leading_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments) } inline void SourceCodeInfo_Location::set_leading_comments(const char* value) { set_has_leading_comments(); - if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_ = new ::std::string; - } - leading_comments_->assign(value); + leading_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_comments) } -inline void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) { +inline void SourceCodeInfo_Location::set_leading_comments(const char* value, + size_t size) { set_has_leading_comments(); - if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_ = new ::std::string; - } - leading_comments_->assign(reinterpret_cast(value), size); + leading_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_comments) } inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() { set_has_leading_comments(); - if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - leading_comments_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments) - return leading_comments_; + return leading_comments_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* SourceCodeInfo_Location::release_leading_comments() { clear_has_leading_comments(); - if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = leading_comments_; - leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return leading_comments_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* SourceCodeInfo_Location::unsafe_arena_release_leading_comments() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_leading_comments(); + return leading_comments_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) { - if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete leading_comments_; + if (leading_comments != NULL) { + set_has_leading_comments(); + } else { + clear_has_leading_comments(); } - if (leading_comments) { + leading_comments_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), leading_comments, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments) +} +inline void SourceCodeInfo_Location::unsafe_arena_set_allocated_leading_comments( + ::std::string* leading_comments) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (leading_comments != NULL) { set_has_leading_comments(); - leading_comments_ = leading_comments; } else { clear_has_leading_comments(); - leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_leading_comments(); + leading_comments_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + leading_comments, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments) } @@ -6622,68 +7603,67 @@ inline void SourceCodeInfo_Location::clear_has_trailing_comments() { _has_bits_[0] &= ~0x00000008u; } inline void SourceCodeInfo_Location::clear_trailing_comments() { - if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_->clear(); - } + trailing_comments_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); clear_has_trailing_comments(); } inline const ::std::string& SourceCodeInfo_Location::trailing_comments() const { // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments) - return *trailing_comments_; + return trailing_comments_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) { set_has_trailing_comments(); - if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_ = new ::std::string; - } - trailing_comments_->assign(value); + trailing_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments) } inline void SourceCodeInfo_Location::set_trailing_comments(const char* value) { set_has_trailing_comments(); - if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_ = new ::std::string; - } - trailing_comments_->assign(value); + trailing_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value), + GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.trailing_comments) } -inline void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) { +inline void SourceCodeInfo_Location::set_trailing_comments(const char* value, + size_t size) { set_has_trailing_comments(); - if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_ = new ::std::string; - } - trailing_comments_->assign(reinterpret_cast(value), size); + trailing_comments_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string( + reinterpret_cast(value), size), GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.trailing_comments) } inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() { set_has_trailing_comments(); - if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - trailing_comments_ = new ::std::string; - } // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments) - return trailing_comments_; + return trailing_comments_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() { clear_has_trailing_comments(); - if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = trailing_comments_; - trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - return temp; - } + return trailing_comments_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); +} +inline ::std::string* SourceCodeInfo_Location::unsafe_arena_release_trailing_comments() { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + clear_has_trailing_comments(); + return trailing_comments_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + GetArenaNoVirtual()); } inline void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) { - if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete trailing_comments_; + if (trailing_comments != NULL) { + set_has_trailing_comments(); + } else { + clear_has_trailing_comments(); } - if (trailing_comments) { + trailing_comments_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), trailing_comments, + GetArenaNoVirtual()); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments) +} +inline void SourceCodeInfo_Location::unsafe_arena_set_allocated_trailing_comments( + ::std::string* trailing_comments) { + GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); + if (trailing_comments != NULL) { set_has_trailing_comments(); - trailing_comments_ = trailing_comments; } else { clear_has_trailing_comments(); - trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + set_has_trailing_comments(); + trailing_comments_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + trailing_comments, GetArenaNoVirtual()); // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments) } @@ -6752,8 +7732,8 @@ inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions return ::google::protobuf::FieldOptions_CType_descriptor(); } -} // namespace google } // namespace protobuf +} // namespace google #endif // SWIG // @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index a753601f..f30f4df5 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -37,6 +37,7 @@ // without any other information (e.g. without reading its imports). +syntax = "proto2"; package google.protobuf; option java_package = "com.google.protobuf"; @@ -74,10 +75,14 @@ message FileDescriptorProto { optional FileOptions options = 8; // This field contains optional information about the original source code. - // You may safely remove this entire field whithout harming runtime + // You may safely remove this entire field without harming runtime // functionality of the descriptors -- the information is needed only by // development tools. optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2" and "proto3". + optional string syntax = 12; } // Describes a message type. @@ -306,7 +311,10 @@ message FileOptions { optional OptimizeMode optimize_for = 9 [default=SPEED]; // Sets the Go package where structs generated from this .proto will be - // placed. There is no default. + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. optional string go_package = 11; @@ -315,7 +323,7 @@ message FileOptions { // are not specific to any particular RPC system. They are generated by the // main code generators in each language (without additional plugins). // Generic services were the only kind of service generation supported by - // early versions of proto2. + // early versions of google.protobuf. // // Generic services are now considered deprecated in favor of using plugins // that generate code specific to your particular RPC system. Therefore, @@ -371,6 +379,29 @@ message MessageOptions { // this is a formalization for deprecating messages. optional bool deprecated = 3 [default=false]; + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementions still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -436,20 +467,6 @@ message FieldOptions { // is a formalization for deprecating fields. optional bool deprecated = 3 [default=false]; - // EXPERIMENTAL. DO NOT USE. - // For "map" fields, the name of the field in the enclosed type that - // is the key for this map. For example, suppose we have: - // message Item { - // required string name = 1; - // required string value = 2; - // } - // message Config { - // repeated Item items = 1 [experimental_map_key="name"]; - // } - // In this situation, the map key for Item will be set to "name". - // TODO: Fully-implement this, then remove the "experimental_" prefix. - optional string experimental_map_key = 9; - // For Google-internal migration only. Do not use. optional bool weak = 10 [default=false]; diff --git a/src/google/protobuf/descriptor_pb2_test.py b/src/google/protobuf/descriptor_pb2_test.py index 48a0d48a..c5a8d8a2 100644 --- a/src/google/protobuf/descriptor_pb2_test.py +++ b/src/google/protobuf/descriptor_pb2_test.py @@ -33,14 +33,14 @@ # Verify that prebuild and checkedin version of descriptor_pb2.py is up to date. from google3.pyglib import resources -import unittest +from google.apputils import basetest _DESC = 'google3/net/proto2/proto/descriptor_pb2.' _OLD = _DESC + 'py-prebuilt' _NEW = _DESC + 'compiled' -class PregeneratedFileChanged(unittest.TestCase): +class PregeneratedFileChanged(basetest.TestCase): def testSameText(self): generated = resources.GetResource(_NEW) @@ -51,4 +51,4 @@ class PregeneratedFileChanged(unittest.TestCase): 'regnerate a new version of %s and add it to your CL' % _OLD) if __name__ == '__main__': - unittest.main() + basetest.main() diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index ac96160c..3e6de803 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -360,6 +360,34 @@ TEST_F(FileDescriptorTest, BuildAgain) { EXPECT_TRUE(pool_.BuildFile(file) == NULL); } +TEST_F(FileDescriptorTest, Syntax) { + FileDescriptorProto proto; + proto.set_name("foo"); + // Enable the test when we also populate the syntax for proto2. +#if 0 + { + proto.set_syntax("proto2"); + DescriptorPool pool; + const FileDescriptor* file = pool.BuildFile(proto); + EXPECT_TRUE(file != NULL); + EXPECT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax()); + FileDescriptorProto other; + file->CopyTo(&other); + EXPECT_EQ("proto2", other.syntax()); + } +#endif + { + proto.set_syntax("proto3"); + DescriptorPool pool; + const FileDescriptor* file = pool.BuildFile(proto); + EXPECT_TRUE(file != NULL); + EXPECT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax()); + FileDescriptorProto other; + file->CopyTo(&other); + EXPECT_EQ("proto3", other.syntax()); + } +} + // =================================================================== // Test simple flat messages and fields. @@ -2157,6 +2185,12 @@ TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) { // Placeholder files should not be findable. EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name())); EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == NULL); + + // Copy*To should not crash for placeholder files. + FileDescriptorProto baz_file_proto; + baz_file->CopyTo(&baz_file_proto); + baz_file->CopySourceCodeInfoTo(&baz_file_proto); + EXPECT_FALSE(baz_file_proto.has_source_code_info()); } TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) { @@ -4736,6 +4770,553 @@ TEST_F(ValidationErrorTest, UnusedImportWarning) { "}"); } +namespace { +void FillValidMapEntry(FileDescriptorProto* file_proto) { + ASSERT_TRUE(TextFormat::ParseFromString( + "name: 'foo.proto' " + "message_type { " + " name: 'Foo' " + " field { " + " name: 'foo_map' number: 1 label:LABEL_REPEATED " + " type_name: 'FooMapEntry' " + " } " + " nested_type { " + " name: 'FooMapEntry' " + " options { map_entry: true } " + " field { " + " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL " + " } " + " field { " + " name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL " + " } " + " } " + "} " + "message_type { " + " name: 'Bar' " + " extension_range { start: 1 end: 10 }" + "} ", + file_proto)); +} +static const char* kMapEntryErrorMessage = + "foo.proto: Foo.foo_map: OTHER: map_entry should not be set explicitly. " + "Use map instead.\n"; +static const char* kMapEntryKeyTypeErrorMessage = + "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, " + "bytes or message types.\n"; + +} // namespace + +TEST_F(ValidationErrorTest, MapEntryBase) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + BuildFile(file_proto.DebugString()); +} + +TEST_F(ValidationErrorTest, MapEntryExtensionRange) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "extension_range { " + " start: 10 end: 20 " + "} ", + file_proto.mutable_message_type(0)->mutable_nested_type(0)); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryExtension) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "extension { " + " name: 'foo_ext' extendee: '.Bar' number: 5" + "} ", + file_proto.mutable_message_type(0)->mutable_nested_type(0)); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryNestedType) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "nested_type { " + " name: 'Bar' " + "} ", + file_proto.mutable_message_type(0)->mutable_nested_type(0)); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryEnumTypes) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "enum_type { " + " name: 'BarEnum' " + " value { name: 'BAR_BAR' number:0 } " + "} ", + file_proto.mutable_message_type(0)->mutable_nested_type(0)); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryExtraField) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "field { " + " name: 'other_field' " + " label: LABEL_OPTIONAL " + " type: TYPE_INT32 " + " number: 3 " + "} ", + file_proto.mutable_message_type(0)->mutable_nested_type(0)); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryMessageName) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name( + "OtherMapEntry"); + file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name( + "OtherMapEntry"); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + file_proto.mutable_message_type(0)->mutable_field(0)->set_label( + FieldDescriptorProto::LABEL_OPTIONAL); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + // Move the nested MapEntry message into the top level, which should not pass + // the validation. + file_proto.mutable_message_type()->AddAllocated( + file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast()); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyName) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_name("Key"); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyLabel) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_label(FieldDescriptorProto::LABEL_REQUIRED); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyNumber) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_number(3); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryValueName) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* value = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(1); + value->set_name("Value"); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryValueLabel) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* value = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(1); + value->set_label(FieldDescriptorProto::LABEL_REQUIRED); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryValueNumber) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* value = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(1); + value->set_number(3); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_type(FieldDescriptorProto::TYPE_FLOAT); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_type(FieldDescriptorProto::TYPE_DOUBLE); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->set_type(FieldDescriptorProto::TYPE_BYTES); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->clear_type(); + key->set_type_name("BarEnum"); + EnumDescriptorProto* enum_proto = file_proto.add_enum_type(); + enum_proto->set_name("BarEnum"); + EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value(); + enum_value_proto->set_name("BAR_VALUE0"); + enum_value_proto->set_number(0); + BuildFileWithErrors(file_proto.DebugString(), + "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot " + "be enum types.\n"); + // Enum keys are not allowed in proto3 as well. + // Get rid of extensions for proto3 to make it proto3 compatible. + file_proto.mutable_message_type()->RemoveLast(); + file_proto.set_syntax("proto3"); + BuildFileWithErrors(file_proto.DebugString(), + "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot " + "be enum types.\n"); +} + + +TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + FieldDescriptorProto* key = file_proto.mutable_message_type(0) + ->mutable_nested_type(0) + ->mutable_field(0); + key->clear_type(); + key->set_type_name(".Bar"); + BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage); +} + +TEST_F(ValidationErrorTest, MapEntryConflictsWithField) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "field { " + " name: 'FooMapEntry' " + " type: TYPE_INT32 " + " label: LABEL_OPTIONAL " + " number: 100 " + "}", + file_proto.mutable_message_type(0)); + BuildFileWithErrors( + file_proto.DebugString(), + "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " + "\"Foo\".\n" + "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n" + "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " + "with an existing field.\n"); +} + +TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "nested_type { " + " name: 'FooMapEntry' " + "}", + file_proto.mutable_message_type(0)); + BuildFileWithErrors( + file_proto.DebugString(), + "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " + "\"Foo\".\n" + "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " + "with an existing nested message type.\n"); +} + +TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "enum_type { " + " name: 'FooMapEntry' " + " value { name: 'ENTRY_FOO' number: 0 }" + "}", + file_proto.mutable_message_type(0)); + BuildFileWithErrors( + file_proto.DebugString(), + "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " + "\"Foo\".\n" + "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " + "with an existing enum type.\n"); +} + +TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) { + FileDescriptorProto file_proto; + FillValidMapEntry(&file_proto); + TextFormat::MergeFromString( + "oneof_decl { " + " name: 'FooMapEntry' " + "}" + "field { " + " name: 'int_field' " + " type: TYPE_INT32 " + " label: LABEL_OPTIONAL " + " oneof_index: 0 " + " number: 100 " + "} ", + file_proto.mutable_message_type(0)); + BuildFileWithErrors( + file_proto.DebugString(), + "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in " + "\"Foo\".\n" + "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n" + "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts " + "with an existing oneof type.\n"); +} + +TEST_F(ValidationErrorTest, Proto3RequiredFields) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } " + "}", + "foo.proto: Foo.foo: OTHER: Required fields are not allowed in " + "proto3.\n"); + + // applied to nested types as well. + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " nested_type { " + " name : 'Bar' " + " field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } " + " } " + "}", + "foo.proto: Foo.Bar.bar: OTHER: Required fields are not allowed in " + "proto3.\n"); + + // optional and repeated fields are OK. + BuildFile( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " + " field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } " + "}"); +} + +TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " default_value: '1' }" + "}", + "foo.proto: Foo.foo: OTHER: Explicit default values are not allowed in " + "proto3.\n"); + + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " nested_type { " + " name : 'Bar' " + " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " default_value: '1' }" + " } " + "}", + "foo.proto: Foo.Bar.bar: OTHER: Explicit default values are not allowed " + "in proto3.\n"); +} + +TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " + " extension_range { start:10 end:100 } " + "}", + "foo.proto: Foo: OTHER: Extension ranges are not allowed in " + "proto3.\n"); + + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " nested_type { " + " name : 'Bar' " + " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } " + " extension_range { start:10 end:100 } " + " } " + "}", + "foo.proto: Foo.Bar: OTHER: Extension ranges are not allowed in " + "proto3.\n"); +} + +TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " options { message_set_wire_format: true } " + "}", + "foo.proto: Foo: OTHER: MessageSet is not supported " + "in proto3.\n"); +} + +TEST_F(ValidationErrorTest, ValidateProto3Enum) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "enum_type { " + " name: 'FooEnum' " + " value { name: 'FOO_FOO' number:1 } " + "}", + "foo.proto: FooEnum: OTHER: The first enum value must be " + "zero in proto3.\n"); + + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " enum_type { " + " name: 'FooEnum' " + " value { name: 'FOO_FOO' number:1 } " + " } " + "}", + "foo.proto: Foo.FooEnum: OTHER: The first enum value must be " + "zero in proto3.\n"); + + // valid case. + BuildFile( + "name: 'foo.proto' " + "syntax: 'proto3' " + "enum_type { " + " name: 'FooEnum' " + " value { name: 'FOO_FOO' number:0 } " + "}"); +} + +TEST_F(ValidationErrorTest, ValidateProto3LiteRuntime) { + // Lite runtime is not supported in proto3. + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "options { " + " optimize_for: LITE_RUNTIME " + "} ", + "foo.proto: foo.proto: OTHER: Lite runtime is not supported " + "in proto3.\n"); +} + + +TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) { + // Define an enum in a proto2 file. + BuildFile( + "name: 'foo.proto' " + "package: 'foo' " + "syntax: 'proto2' " + "enum_type { " + " name: 'FooEnum' " + " value { name: 'DEFAULT_OPTION' number:0 } " + "}"); + + // Now try to refer to it. (All tests in the fixture use the same pool, so we + // can refer to the enum above in this definition.) + BuildFileWithErrors( + "name: 'bar.proto' " + "dependency: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM " + " type_name: 'foo.FooEnum' }" + "}", + "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not a proto3 " + "enum, but is used in \"Foo\" which is a proto3 message type.\n"); +} + +TEST_F(ValidationErrorTest, ValidateProto3Extension) { + // Valid for options. + DescriptorPool pool; + FileDescriptorProto file_proto; + // Add "google/protobuf/descriptor.proto". + FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto); + ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); + // Add "foo.proto": + // import "google/protobuf/descriptor.proto"; + // extend google.protobuf.FieldOptions { + // optional int32 option1 = 1000; + // } + file_proto.Clear(); + file_proto.set_name("foo.proto"); + file_proto.set_syntax("proto3"); + file_proto.add_dependency("google/protobuf/descriptor.proto"); + AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000, + FieldDescriptorProto::LABEL_OPTIONAL, + FieldDescriptorProto::TYPE_INT32); + ASSERT_TRUE(pool.BuildFile(file_proto) != NULL); + + // Copy and change the package of the descriptor.proto + BuildFile( + "name: 'google.protobuf.proto' " + "syntax: 'proto2' " + "message_type { " + " name: 'Container' extension_range { start: 1 end: 1000 } " + "}"); + BuildFileWithErrors( + "name: 'bar.proto' " + "syntax: 'proto3' " + "dependency: 'google.protobuf.proto' " + "extension { " + " name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 " + " extendee: 'Container' " + "}", + "bar.proto: bar: OTHER: Extensions in proto3 are only allowed for " + "defining options.\n"); +} // =================================================================== // DescriptorDatabase diff --git a/src/google/protobuf/drop_unknown_fields_test.cc b/src/google/protobuf/drop_unknown_fields_test.cc new file mode 100644 index 00000000..2a672c7a --- /dev/null +++ b/src/google/protobuf/drop_unknown_fields_test.cc @@ -0,0 +1,88 @@ +// 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 +#ifndef _SHARED_PTR_H +#include +#endif + +#include +#include +#include + +namespace google { +using unittest_drop_unknown_fields::Foo; +using unittest_drop_unknown_fields::FooWithExtraFields; + +namespace protobuf { + +TEST(DropUnknownFieldsTest, GeneratedMessage) { + FooWithExtraFields foo_with_extra_fields; + foo_with_extra_fields.set_int32_value(1); + foo_with_extra_fields.set_enum_value(FooWithExtraFields::QUX); + foo_with_extra_fields.set_extra_int32_value(2); + + Foo foo; + ASSERT_TRUE(foo.ParseFromString(foo_with_extra_fields.SerializeAsString())); + EXPECT_EQ(1, foo.int32_value()); + EXPECT_EQ(static_cast(FooWithExtraFields::QUX), + static_cast(foo.enum_value())); + // We don't generate unknown field accessors but the UnknownFieldSet is + // still exposed through reflection API. + EXPECT_TRUE(foo.GetReflection()->GetUnknownFields(foo).empty()); + + ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo.SerializeAsString())); + EXPECT_EQ(1, foo_with_extra_fields.int32_value()); + EXPECT_EQ(FooWithExtraFields::QUX, foo_with_extra_fields.enum_value()); + // The "extra_int32_value" field should be lost. + EXPECT_EQ(0, foo_with_extra_fields.extra_int32_value()); +} + +TEST(DropUnknownFieldsTest, DynamicMessage) { + FooWithExtraFields foo_with_extra_fields; + foo_with_extra_fields.set_int32_value(1); + foo_with_extra_fields.set_enum_value(FooWithExtraFields::QUX); + foo_with_extra_fields.set_extra_int32_value(2); + + google::protobuf::DynamicMessageFactory factory; + scoped_ptr foo( + factory.GetPrototype(Foo::descriptor())->New()); + ASSERT_TRUE(foo->ParseFromString(foo_with_extra_fields.SerializeAsString())); + EXPECT_TRUE(foo->GetReflection()->GetUnknownFields(*foo).empty()); + + ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo->SerializeAsString())); + EXPECT_EQ(1, foo_with_extra_fields.int32_value()); + EXPECT_EQ(FooWithExtraFields::QUX, foo_with_extra_fields.enum_value()); + // The "extra_int32_value" field should be lost. + EXPECT_EQ(0, foo_with_extra_fields.extra_int32_value()); +} + +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 4cca9869..db1dd4d3 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,8 @@ using internal::ExtensionSet; using internal::GeneratedMessageReflection; +using internal::ArenaStringPtr; + // =================================================================== // Some helper tables and functions... @@ -131,7 +134,7 @@ int FieldSpaceUsed(const FieldDescriptor* field) { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: - return sizeof(string*); + return sizeof(ArenaStringPtr); } break; } @@ -162,7 +165,7 @@ int OneofFieldSpaceUsed(const FieldDescriptor* field) { switch (field->options().ctype()) { default: case FieldOptions::STRING: - return sizeof(string*); + return sizeof(ArenaStringPtr); } break; } @@ -236,6 +239,8 @@ class DynamicMessage : public Message { // implements Message ---------------------------------------------- Message* New() const; + Message* New(::google::protobuf::Arena* arena) const; + ::google::protobuf::Arena* GetArena() const { return NULL; }; int GetCachedSize() const; void SetCachedSize(int size) const; @@ -245,6 +250,8 @@ class DynamicMessage : public Message { private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); + DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena); + void SharedCtor(); inline bool is_prototype() const { return type_info_->prototype == this || @@ -261,7 +268,6 @@ class DynamicMessage : public Message { } const TypeInfo* type_info_; - // TODO(kenton): Make this an atomic when C++ supports it. mutable int cached_byte_size_; }; @@ -269,6 +275,17 @@ class DynamicMessage : public Message { DynamicMessage::DynamicMessage(const TypeInfo* type_info) : type_info_(type_info), cached_byte_size_(0) { + SharedCtor(); +} + +DynamicMessage::DynamicMessage(const TypeInfo* type_info, + ::google::protobuf::Arena* arena) + : type_info_(type_info), + cached_byte_size_(0) { + SharedCtor(); +} + +void DynamicMessage::SharedCtor() { // We need to call constructors for various fields manually and set // default values where appropriate. We use placement new to call // constructors. If you haven't heard of placement new, I suggest Googling @@ -330,15 +347,17 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info) default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: if (!field->is_repeated()) { + const string* default_value; if (is_prototype()) { - new(field_ptr) const string*(&field->default_value_string()); + default_value = &field->default_value_string(); } else { - string* default_value = - *reinterpret_cast( + default_value = + &(reinterpret_cast( type_info_->prototype->OffsetToPointer( - type_info_->offsets[i])); - new(field_ptr) string*(default_value); + type_info_->offsets[i]))->Get(NULL)); } + ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr(); + asp->UnsafeSetDefault(default_value); } else { new(field_ptr) RepeatedPtrField(); } @@ -390,9 +409,15 @@ DynamicMessage::~DynamicMessage() { if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { switch (field->options().ctype()) { default: - case FieldOptions::STRING: - delete *reinterpret_cast(field_ptr); + case FieldOptions::STRING: { + const ::std::string* default_value = + &(reinterpret_cast( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i]))->Get(NULL)); + reinterpret_cast(field_ptr)->Destroy(default_value, + NULL); break; + } } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { delete *reinterpret_cast(field_ptr); @@ -440,10 +465,12 @@ DynamicMessage::~DynamicMessage() { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { - string* ptr = *reinterpret_cast(field_ptr); - if (ptr != &field->default_value_string()) { - delete ptr; - } + const ::std::string* default_value = + &(reinterpret_cast( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i]))->Get(NULL)); + reinterpret_cast(field_ptr)->Destroy(default_value, + NULL); break; } } @@ -492,6 +519,16 @@ Message* DynamicMessage::New() const { return new(new_base) DynamicMessage(type_info_); } +Message* DynamicMessage::New(::google::protobuf::Arena* arena) const { + if (arena != NULL) { + Message* message = New(); + arena->Own(message); + return message; + } else { + return New(); + } +} + int DynamicMessage::GetCachedSize() const { return cached_byte_size_; } @@ -672,7 +709,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->oneof_case_offset, type_info->pool, this, - type_info->size)); + type_info->size, + -1 /* arena_offset */)); } else { type_info->reflection.reset( new GeneratedMessageReflection( @@ -684,7 +722,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->extensions_offset, type_info->pool, this, - type_info->size)); + type_info->size, + -1 /* arena_offset */)); } // Cross link prototypes. prototype->CrossLinkPrototypes(); @@ -723,12 +762,8 @@ void DynamicMessageFactory::ConstructDefaultOneofInstance( switch (field->options().ctype()) { default: case FieldOptions::STRING: - if (field->has_default_value()) { - new(field_ptr) const string*(&field->default_value_string()); - } else { - new(field_ptr) string*( - const_cast(&internal::GetEmptyString())); - } + ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr(); + asp->UnsafeSetDefault(&field->default_value_string()); break; } break; diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index 10ed7005..1e947e6d 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -39,6 +39,9 @@ #define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index a1c1661b..6353ecbf 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -226,5 +226,13 @@ TEST_F(DynamicMessageTest, SpaceUsed) { EXPECT_LT(initial_space_used, message->SpaceUsed()); } +TEST_F(DynamicMessageTest, Arena) { + Arena arena; + Message* message = prototype_->New(&arena); + (void)message; // avoid unused-variable error. + // Return without freeing: should not leak. +} + + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 274554b5..d6ebe4c3 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -174,12 +174,21 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* containing_type, // =================================================================== // Constructors and basic methods. -ExtensionSet::ExtensionSet() {} +ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena) : arena_(arena) { + if (arena_ != NULL) { + arena_->OwnDestructor(&extensions_); + } +} + +ExtensionSet::ExtensionSet() : arena_(NULL) {} ExtensionSet::~ExtensionSet() { - for (map::iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { - iter->second.Free(); + // Deletes all allocated extensions. + if (arena_ == NULL) { + for (map::iterator iter = extensions_.begin(); + iter != extensions_.end(); ++iter) { + iter->second.Free(); + } } } @@ -301,7 +310,8 @@ void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = true; \ extension->is_packed = packed; \ - extension->repeated_##LOWERCASE##_value = new RepeatedField(); \ + extension->repeated_##LOWERCASE##_value = \ + Arena::Create >(arena_, arena_); \ } else { \ GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \ GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ @@ -345,34 +355,44 @@ void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type, switch (WireFormatLite::FieldTypeToCppType( static_cast(field_type))) { case WireFormatLite::CPPTYPE_INT32: - extension->repeated_int32_value = new RepeatedField(); + extension->repeated_int32_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_INT64: - extension->repeated_int64_value = new RepeatedField(); + extension->repeated_int64_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_UINT32: - extension->repeated_uint32_value = new RepeatedField(); + extension->repeated_uint32_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_UINT64: - extension->repeated_uint64_value = new RepeatedField(); + extension->repeated_uint64_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_DOUBLE: - extension->repeated_double_value = new RepeatedField(); + extension->repeated_double_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_FLOAT: - extension->repeated_float_value = new RepeatedField(); + extension->repeated_float_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_BOOL: - extension->repeated_bool_value = new RepeatedField(); + extension->repeated_bool_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_ENUM: - extension->repeated_enum_value = new RepeatedField(); + extension->repeated_enum_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_STRING: - extension->repeated_string_value = new RepeatedPtrField< ::std::string>(); + extension->repeated_string_value = + Arena::Create >(arena_, arena_); break; case WireFormatLite::CPPTYPE_MESSAGE: - extension->repeated_message_value = new RepeatedPtrField(); + extension->repeated_message_value = + Arena::Create >(arena_, arena_); break; } } @@ -444,7 +464,8 @@ void ExtensionSet::AddEnum(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = true; extension->is_packed = packed; - extension->repeated_enum_value = new RepeatedField(); + extension->repeated_enum_value = + Arena::Create >(arena_, arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM); GOOGLE_DCHECK_EQ(extension->is_packed, packed); @@ -474,7 +495,7 @@ string* ExtensionSet::MutableString(int number, FieldType type, extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = false; - extension->string_value = new string; + extension->string_value = Arena::Create(arena_); } else { GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING); } @@ -504,7 +525,8 @@ string* ExtensionSet::AddString(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = true; extension->is_packed = false; - extension->repeated_string_value = new RepeatedPtrField(); + extension->repeated_string_value = + Arena::Create >(arena_, arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING); } @@ -544,7 +566,7 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_lazy = false; - extension->message_value = prototype.New(); + extension->message_value = prototype.New(arena_); extension->is_cleared = false; return extension->message_value; } else { @@ -576,14 +598,32 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_lazy = false; - extension->message_value = message; + if (message->GetArena() == arena_) { + extension->message_value = message; + } else { + extension->message_value = message->New(arena_); + extension->message_value->CheckTypeAndMergeFrom(*message); + if (message->GetArena() == NULL) { + delete message; + } + } } else { GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); if (extension->is_lazy) { extension->lazymessage_value->SetAllocatedMessage(message); } else { - delete extension->message_value; - extension->message_value = message; + if (arena_ == NULL) { + delete extension->message_value; + } + if (message->GetArena() == arena_) { + extension->message_value = message; + } else { + extension->message_value = message->New(arena_); + extension->message_value->CheckTypeAndMergeFrom(*message); + if (message->GetArena() == NULL) { + delete message; + } + } } } extension->is_cleared = false; @@ -600,7 +640,39 @@ MessageLite* ExtensionSet::ReleaseMessage(int number, MessageLite* ret = NULL; if (iter->second.is_lazy) { ret = iter->second.lazymessage_value->ReleaseMessage(prototype); - delete iter->second.lazymessage_value; + if (arena_ == NULL) { + delete iter->second.lazymessage_value; + } + } else { + if (arena_ == NULL) { + ret = iter->second.message_value; + } else { + // ReleaseMessage() always returns a heap-allocated message, and we are + // on an arena, so we need to make a copy of this message to return. + ret = (iter->second.message_value)->New(); + ret->CheckTypeAndMergeFrom(*iter->second.message_value); + } + } + extensions_.erase(number); + return ret; + } +} + +MessageLite* ExtensionSet::UnsafeArenaReleaseMessage( + int number, const MessageLite& prototype) { + map::iterator iter = extensions_.find(number); + if (iter == extensions_.end()) { + // Not present. Return NULL. + return NULL; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); + MessageLite* ret = NULL; + if (iter->second.is_lazy) { + ret = + iter->second.lazymessage_value->UnsafeArenaReleaseMessage(prototype); + if (arena_ == NULL) { + delete iter->second.lazymessage_value; + } } else { ret = iter->second.message_value; } @@ -637,7 +709,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = - new RepeatedPtrField(); + Arena::Create >(arena_, arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } @@ -647,7 +719,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, MessageLite* result = extension->repeated_message_value ->AddFromCleared >(); if (result == NULL) { - result = prototype.New(); + result = prototype.New(arena_); extension->repeated_message_value->AddAllocated(result); } return result; @@ -765,138 +837,142 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { for (map::const_iterator iter = other.extensions_.begin(); iter != other.extensions_.end(); ++iter) { const Extension& other_extension = iter->second; + InternalExtensionMergeFrom(iter->first, other_extension); + } +} - if (other_extension.is_repeated) { - Extension* extension; - bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor, - &extension); - if (is_new) { - // Extension did not already exist in set. - extension->type = other_extension.type; - extension->is_packed = other_extension.is_packed; - extension->is_repeated = true; - } else { - GOOGLE_DCHECK_EQ(extension->type, other_extension.type); - GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed); - GOOGLE_DCHECK(extension->is_repeated); - } +void ExtensionSet::InternalExtensionMergeFrom( + int number, const Extension& other_extension) { + if (other_extension.is_repeated) { + Extension* extension; + bool is_new = MaybeNewExtension(number, other_extension.descriptor, + &extension); + if (is_new) { + // Extension did not already exist in set. + extension->type = other_extension.type; + extension->is_packed = other_extension.is_packed; + extension->is_repeated = true; + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed); + GOOGLE_DCHECK(extension->is_repeated); + } - switch (cpp_type(other_extension.type)) { -#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ - case WireFormatLite::CPPTYPE_##UPPERCASE: \ - if (is_new) { \ - extension->repeated_##LOWERCASE##_value = \ - new REPEATED_TYPE; \ - } \ - extension->repeated_##LOWERCASE##_value->MergeFrom( \ - *other_extension.repeated_##LOWERCASE##_value); \ - break; + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + if (is_new) { \ + extension->repeated_##LOWERCASE##_value = \ + Arena::Create(arena_, arena_); \ + } \ + extension->repeated_##LOWERCASE##_value->MergeFrom( \ + *other_extension.repeated_##LOWERCASE##_value); \ + break; - HANDLE_TYPE( INT32, int32, RepeatedField < int32>); - HANDLE_TYPE( INT64, int64, RepeatedField < int64>); - HANDLE_TYPE( UINT32, uint32, RepeatedField < uint32>); - HANDLE_TYPE( UINT64, uint64, RepeatedField < uint64>); - HANDLE_TYPE( FLOAT, float, RepeatedField < float>); - HANDLE_TYPE( DOUBLE, double, RepeatedField < double>); - HANDLE_TYPE( BOOL, bool, RepeatedField < bool>); - HANDLE_TYPE( ENUM, enum, RepeatedField < int>); - HANDLE_TYPE( STRING, string, RepeatedPtrField< string>); + HANDLE_TYPE( INT32, int32, RepeatedField < int32>); + HANDLE_TYPE( INT64, int64, RepeatedField < int64>); + HANDLE_TYPE( UINT32, uint32, RepeatedField < uint32>); + HANDLE_TYPE( UINT64, uint64, RepeatedField < uint64>); + HANDLE_TYPE( FLOAT, float, RepeatedField < float>); + HANDLE_TYPE( DOUBLE, double, RepeatedField < double>); + HANDLE_TYPE( BOOL, bool, RepeatedField < bool>); + HANDLE_TYPE( ENUM, enum, RepeatedField < int>); + HANDLE_TYPE( STRING, string, RepeatedPtrField< string>); #undef HANDLE_TYPE - case WireFormatLite::CPPTYPE_MESSAGE: - if (is_new) { - extension->repeated_message_value = - new RepeatedPtrField(); - } - // We can't call RepeatedPtrField::MergeFrom() because - // it would attempt to allocate new objects. - RepeatedPtrField* other_repeated_message = - other_extension.repeated_message_value; - for (int i = 0; i < other_repeated_message->size(); i++) { - const MessageLite& other_message = other_repeated_message->Get(i); - MessageLite* target = extension->repeated_message_value - ->AddFromCleared >(); - if (target == NULL) { - target = other_message.New(); - extension->repeated_message_value->AddAllocated(target); - } - target->CheckTypeAndMergeFrom(other_message); + case WireFormatLite::CPPTYPE_MESSAGE: + if (is_new) { + extension->repeated_message_value = + Arena::Create >(arena_, arena_); + } + // We can't call RepeatedPtrField::MergeFrom() because + // it would attempt to allocate new objects. + RepeatedPtrField* other_repeated_message = + other_extension.repeated_message_value; + for (int i = 0; i < other_repeated_message->size(); i++) { + const MessageLite& other_message = other_repeated_message->Get(i); + MessageLite* target = extension->repeated_message_value + ->AddFromCleared >(); + if (target == NULL) { + target = other_message.New(arena_); + extension->repeated_message_value->AddAllocated(target); } + target->CheckTypeAndMergeFrom(other_message); + } + break; + } + } else { + if (!other_extension.is_cleared) { + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ + case WireFormatLite::CPPTYPE_##UPPERCASE: \ + Set##CAMELCASE(number, other_extension.type, \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ break; - } - } else { - if (!other_extension.is_cleared) { - switch (cpp_type(other_extension.type)) { -#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ - case WireFormatLite::CPPTYPE_##UPPERCASE: \ - Set##CAMELCASE(iter->first, other_extension.type, \ - other_extension.LOWERCASE##_value, \ - other_extension.descriptor); \ - break; - - HANDLE_TYPE( INT32, int32, Int32); - HANDLE_TYPE( INT64, int64, Int64); - HANDLE_TYPE(UINT32, uint32, UInt32); - HANDLE_TYPE(UINT64, uint64, UInt64); - HANDLE_TYPE( FLOAT, float, Float); - HANDLE_TYPE(DOUBLE, double, Double); - HANDLE_TYPE( BOOL, bool, Bool); - HANDLE_TYPE( ENUM, enum, Enum); + + HANDLE_TYPE( INT32, int32, Int32); + HANDLE_TYPE( INT64, int64, Int64); + HANDLE_TYPE(UINT32, uint32, UInt32); + HANDLE_TYPE(UINT64, uint64, UInt64); + HANDLE_TYPE( FLOAT, float, Float); + HANDLE_TYPE(DOUBLE, double, Double); + HANDLE_TYPE( BOOL, bool, Bool); + HANDLE_TYPE( ENUM, enum, Enum); #undef HANDLE_TYPE - case WireFormatLite::CPPTYPE_STRING: - SetString(iter->first, other_extension.type, - *other_extension.string_value, - other_extension.descriptor); - break; - case WireFormatLite::CPPTYPE_MESSAGE: { - Extension* extension; - bool is_new = MaybeNewExtension(iter->first, - other_extension.descriptor, - &extension); - if (is_new) { - extension->type = other_extension.type; - extension->is_packed = other_extension.is_packed; - extension->is_repeated = false; - if (other_extension.is_lazy) { - extension->is_lazy = true; - extension->lazymessage_value = - other_extension.lazymessage_value->New(); + case WireFormatLite::CPPTYPE_STRING: + SetString(number, other_extension.type, + *other_extension.string_value, + other_extension.descriptor); + break; + case WireFormatLite::CPPTYPE_MESSAGE: { + Extension* extension; + bool is_new = MaybeNewExtension(number, + other_extension.descriptor, + &extension); + if (is_new) { + extension->type = other_extension.type; + extension->is_packed = other_extension.is_packed; + extension->is_repeated = false; + if (other_extension.is_lazy) { + extension->is_lazy = true; + extension->lazymessage_value = + other_extension.lazymessage_value->New(arena_); + extension->lazymessage_value->MergeFrom( + *other_extension.lazymessage_value); + } else { + extension->is_lazy = false; + extension->message_value = + other_extension.message_value->New(arena_); + extension->message_value->CheckTypeAndMergeFrom( + *other_extension.message_value); + } + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed); + GOOGLE_DCHECK(!extension->is_repeated); + if (other_extension.is_lazy) { + if (extension->is_lazy) { extension->lazymessage_value->MergeFrom( *other_extension.lazymessage_value); } else { - extension->is_lazy = false; - extension->message_value = - other_extension.message_value->New(); extension->message_value->CheckTypeAndMergeFrom( - *other_extension.message_value); + other_extension.lazymessage_value->GetMessage( + *extension->message_value)); } } else { - GOOGLE_DCHECK_EQ(extension->type, other_extension.type); - GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed); - GOOGLE_DCHECK(!extension->is_repeated); - if (other_extension.is_lazy) { - if (extension->is_lazy) { - extension->lazymessage_value->MergeFrom( - *other_extension.lazymessage_value); - } else { - extension->message_value->CheckTypeAndMergeFrom( - other_extension.lazymessage_value->GetMessage( - *extension->message_value)); - } + if (extension->is_lazy) { + extension->lazymessage_value->MutableMessage( + *other_extension.message_value)->CheckTypeAndMergeFrom( + *other_extension.message_value); } else { - if (extension->is_lazy) { - extension->lazymessage_value->MutableMessage( - *other_extension.message_value)->CheckTypeAndMergeFrom( - *other_extension.message_value); - } else { - extension->message_value->CheckTypeAndMergeFrom( - *other_extension.message_value); - } + extension->message_value->CheckTypeAndMergeFrom( + *other_extension.message_value); } } - extension->is_cleared = false; - break; } + extension->is_cleared = false; + break; } } } @@ -904,7 +980,19 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { } void ExtensionSet::Swap(ExtensionSet* x) { - extensions_.swap(x->extensions_); + if (GetArenaNoVirtual() == x->GetArenaNoVirtual()) { + extensions_.swap(x->extensions_); + } else { + // TODO(cfallin, rohananil): We maybe able to optimize a case where we are + // swapping from heap to arena-allocated extension set, by just Own()'ing + // the extensions. + ExtensionSet extension_set; + extension_set.MergeFrom(*x); + x->Clear(); + x->MergeFrom(*this); + Clear(); + MergeFrom(extension_set); + } } void ExtensionSet::SwapExtension(ExtensionSet* other, @@ -920,18 +1008,42 @@ void ExtensionSet::SwapExtension(ExtensionSet* other, if (this_iter != extensions_.end() && other_iter != other->extensions_.end()) { - std::swap(this_iter->second, other_iter->second); + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + using std::swap; + swap(this_iter->second, other_iter->second); + } else { + // TODO(cfallin, rohananil): We could further optimize these cases, + // especially avoid creation of ExtensionSet, and move MergeFrom logic + // into Extensions itself (which takes arena as an argument). + // We do it this way to reuse the copy-across-arenas logic already + // implemented in ExtensionSet's MergeFrom. + ExtensionSet temp; + temp.InternalExtensionMergeFrom(number, other_iter->second); + map::iterator temp_iter = temp.extensions_.find(number); + other_iter->second.Clear(); + other->InternalExtensionMergeFrom(number, this_iter->second); + this_iter->second.Clear(); + InternalExtensionMergeFrom(number, temp_iter->second); + } return; } if (this_iter == extensions_.end()) { - extensions_.insert(make_pair(number, other_iter->second)); + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + extensions_.insert(make_pair(number, other_iter->second)); + } else { + InternalExtensionMergeFrom(number, other_iter->second); + } other->extensions_.erase(number); return; } if (other_iter == other->extensions_.end()) { - other->extensions_.insert(make_pair(number, this_iter->second)); + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + other->extensions_.insert(make_pair(number, this_iter->second)); + } else { + other->InternalExtensionMergeFrom(number, this_iter->second); + } extensions_.erase(number); return; } @@ -1223,7 +1335,7 @@ bool ExtensionSet::MaybeNewExtension(int number, const FieldDescriptor* descriptor, Extension** result) { pair::iterator, bool> insert_result = - extensions_.insert(make_pair(number, Extension())); + extensions_.insert(make_pair(number, Extension())); *result = &insert_result.first->second; (*result)->descriptor = descriptor; return insert_result.second; @@ -1554,6 +1666,8 @@ int ExtensionSet::Extension::GetSize() const { return 0; } +// This function deletes all allocated objects. This function should be only +// called if the Extension was created with an arena. void ExtensionSet::Extension::Free() { if (is_repeated) { switch (cpp_type(type)) { diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index d6fc45df..6d6702b3 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -51,6 +51,7 @@ namespace google { namespace protobuf { + class Arena; class Descriptor; // descriptor.h class FieldDescriptor; // descriptor.h class DescriptorPool; // descriptor.h @@ -157,6 +158,7 @@ class MessageSetFieldSkipper; class LIBPROTOBUF_EXPORT ExtensionSet { public: ExtensionSet(); + explicit ExtensionSet(::google::protobuf::Arena* arena); ~ExtensionSet(); // These are called at startup by protocol-compiler-generated code to @@ -261,9 +263,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const FieldDescriptor* descriptor, MessageLite* message); MessageLite* ReleaseMessage(int number, const MessageLite& prototype); + MessageLite* UnsafeArenaReleaseMessage( + int number, const MessageLite& prototype); + MessageLite* ReleaseMessage(const FieldDescriptor* descriptor, MessageFactory* factory); #undef desc + ::google::protobuf::Arena* GetArenaNoVirtual() const { return arena_; } // repeated fields ------------------------------------------------- @@ -421,12 +427,14 @@ class LIBPROTOBUF_EXPORT ExtensionSet { LazyMessageExtension() {} virtual ~LazyMessageExtension() {} - virtual LazyMessageExtension* New() const = 0; + virtual LazyMessageExtension* New(::google::protobuf::Arena* arena) const = 0; virtual const MessageLite& GetMessage( const MessageLite& prototype) const = 0; virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0; virtual void SetAllocatedMessage(MessageLite *message) = 0; virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0; + virtual MessageLite* UnsafeArenaReleaseMessage( + const MessageLite& prototype) = 0; virtual bool IsInitialized() const = 0; virtual int ByteSize() const = 0; @@ -524,6 +532,9 @@ class LIBPROTOBUF_EXPORT ExtensionSet { }; + // Merges existing Extension from other_extension + void InternalExtensionMergeFrom(int number, const Extension& other_extension); + // Returns true and fills field_number and extension if extension is found. // Note to support packed repeated field compatibility, it also fills whether // the tag on wire is packed, which can be different from @@ -569,7 +580,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet { ExtensionFinder* extension_finder, MessageSetFieldSkipper* field_skipper); - // Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This // friendship should automatically extend to ExtensionSet::Extension, but // unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this @@ -587,7 +597,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // for 100 elements or more. Also, we want AppendToList() to order fields // by field number. std::map extensions_; - + ::google::protobuf::Arena* arena_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); }; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index eae4d574..5f4ca1c3 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -169,7 +169,7 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, const MessageLite* prototype = factory->GetPrototype(descriptor->message_type()); extension->is_lazy = false; - extension->message_value = prototype->New(); + extension->message_value = prototype->New(arena_); extension->is_cleared = false; return extension->message_value; } else { @@ -196,9 +196,16 @@ MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, if (iter->second.is_lazy) { ret = iter->second.lazymessage_value->ReleaseMessage( *factory->GetPrototype(descriptor->message_type())); - delete iter->second.lazymessage_value; + if (arena_ == NULL) { + delete iter->second.lazymessage_value; + } } else { - ret = iter->second.message_value; + if (arena_ != NULL) { + ret = (iter->second.message_value)->New(); + ret->CheckTypeAndMergeFrom(*(iter->second.message_value)); + } else { + ret = iter->second.message_value; + } } extensions_.erase(descriptor->number()); return ret; @@ -213,7 +220,7 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = - new RepeatedPtrField(); + ::google::protobuf::Arena::Create >(arena_, arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } @@ -230,7 +237,7 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, } else { prototype = &extension->repeated_message_value->Get(0); } - result = prototype->New(); + result = prototype->New(arena_); extension->repeated_message_value->AddAllocated(result); } return result; diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 8a00bafd..b9d07353 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -319,6 +320,117 @@ TEST(ExtensionSetTest, SwapExtensionBothFull) { TestUtil::ExpectAllExtensionsSet(message2); } +TEST(ExtensionSetTest, ArenaSetAllExtension) { + ::google::protobuf::Arena arena1; + unittest::TestAllExtensions* message1 = + ::google::protobuf::Arena::CreateMessage(&arena1); + TestUtil::SetAllExtensions(message1); + TestUtil::ExpectAllExtensionsSet(*message1); +} + +TEST(ExtensionSetTest, ArenaCopyConstructor) { + ::google::protobuf::Arena arena1; + unittest::TestAllExtensions* message1 = + ::google::protobuf::Arena::CreateMessage(&arena1); + TestUtil::SetAllExtensions(message1); + unittest::TestAllExtensions message2(*message1); + arena1.Reset(); + TestUtil::ExpectAllExtensionsSet(message2); +} + +TEST(ExtensionSetTest, ArenaMergeFrom) { + ::google::protobuf::Arena arena1; + unittest::TestAllExtensions* message1 = + ::google::protobuf::Arena::CreateMessage(&arena1); + TestUtil::SetAllExtensions(message1); + unittest::TestAllExtensions message2; + message2.MergeFrom(*message1); + arena1.Reset(); + TestUtil::ExpectAllExtensionsSet(message2); +} + +TEST(ExtensionSetTest, ArenaSetAllocatedMessageAndRelease) { + ::google::protobuf::Arena arena; + unittest::TestAllExtensions* message = + ::google::protobuf::Arena::CreateMessage(&arena); + EXPECT_FALSE(message->HasExtension( + unittest::optional_foreign_message_extension)); + // Add a extension using SetAllocatedExtension + unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage(); + message->SetAllocatedExtension(unittest::optional_foreign_message_extension, + foreign_message); + // foreign_message is copied underneath, as foreign_message is on heap + // and extension_set is on an arena. + EXPECT_NE(foreign_message, + message->MutableExtension( + unittest::optional_foreign_message_extension)); + + // Underlying message is copied, and returned. + unittest::ForeignMessage* released_message = message->ReleaseExtension( + unittest::optional_foreign_message_extension); + delete released_message; + EXPECT_FALSE(message->HasExtension( + unittest::optional_foreign_message_extension)); +} + +TEST(ExtensionSetTest, SwapExtensionBothFullWithArena) { + ::google::protobuf::Arena arena1; + scoped_ptr arena2(new ::google::protobuf::Arena()); + + unittest::TestAllExtensions* message1 = + Arena::CreateMessage(&arena1); + unittest::TestAllExtensions* message2 = + Arena::CreateMessage(arena2.get()); + + TestUtil::SetAllExtensions(message1); + TestUtil::SetAllExtensions(message2); + message1->SetExtension(unittest::optional_int32_extension, 1); + message2->SetExtension(unittest::optional_int32_extension, 2); + message1->Swap(message2); + EXPECT_EQ(2, message1->GetExtension(unittest::optional_int32_extension)); + EXPECT_EQ(1, message2->GetExtension(unittest::optional_int32_extension)); + // Re-set the original values so ExpectAllExtensionsSet is happy. + message1->SetExtension(unittest::optional_int32_extension, 101); + message2->SetExtension(unittest::optional_int32_extension, 101); + TestUtil::ExpectAllExtensionsSet(*message1); + TestUtil::ExpectAllExtensionsSet(*message2); + arena2.reset(NULL); + TestUtil::ExpectAllExtensionsSet(*message1); + // Test corner cases, when one is empty and other is not. + ::google::protobuf::Arena arena3, arena4; + + unittest::TestAllExtensions* message3 = + Arena::CreateMessage(&arena3); + unittest::TestAllExtensions* message4 = + Arena::CreateMessage(&arena4); + TestUtil::SetAllExtensions(message3); + message3->Swap(message4); + arena3.Reset(); + TestUtil::ExpectAllExtensionsSet(*message4); +} + +TEST(ExtensionSetTest, SwapFieldsOfExtensionBothFullWithArena) { + google::protobuf::Arena arena1; + google::protobuf::Arena* arena2 = new ::google::protobuf::Arena(); + + unittest::TestAllExtensions* message1 = + Arena::CreateMessage(&arena1); + unittest::TestAllExtensions* message2 = + Arena::CreateMessage(arena2); + + TestUtil::SetAllExtensions(message1); + TestUtil::SetAllExtensions(message2); + + const Reflection* reflection = message1->GetReflection(); + vector fields; + reflection->ListFields(*message1, &fields); + reflection->SwapFields(message1, message2, fields); + TestUtil::ExpectAllExtensionsSet(*message1); + TestUtil::ExpectAllExtensionsSet(*message2); + delete arena2; + TestUtil::ExpectAllExtensionsSet(*message1); +} + TEST(ExtensionSetTest, SwapExtensionWithSelf) { unittest::TestAllExtensions message1; diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 536de7d9..ea97aebc 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -74,6 +74,19 @@ const string& NameOfEnum(const EnumDescriptor* descriptor, int value) { return (d == NULL ? GetEmptyString() : d->name()); } +namespace { +inline bool SupportsArenas(const Descriptor* descriptor) { + // In open-source release we enable arena support by default but as we also + // down-integrate descriptor.pb.(h|cc) from our internal code base which + // hasn't enabled arena support yet, here we need to be able to handle both + // cases for descriptor protos. + if (!Arena::is_arena_constructable::type::value) { + return descriptor->name() != "google/protobuf/descriptor.proto"; + } + return true; +} +} // anonymous namespace + // =================================================================== // Helpers for reporting usage errors (e.g. trying to use GetInt32() on // a string field). @@ -177,13 +190,15 @@ GeneratedMessageReflection::GeneratedMessageReflection( int extensions_offset, const DescriptorPool* descriptor_pool, MessageFactory* factory, - int object_size) + int object_size, + int arena_offset) : descriptor_ (descriptor), default_instance_ (default_instance), offsets_ (offsets), has_bits_offset_ (has_bits_offset), unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), + arena_offset_ (arena_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -202,7 +217,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( int oneof_case_offset, const DescriptorPool* descriptor_pool, MessageFactory* factory, - int object_size) + int object_size, + int arena_offset) : descriptor_ (descriptor), default_instance_ (default_instance), default_oneof_instance_ (default_oneof_instance), @@ -211,6 +227,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( oneof_case_offset_(oneof_case_offset), unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), + arena_offset_ (arena_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -220,14 +237,39 @@ GeneratedMessageReflection::GeneratedMessageReflection( GeneratedMessageReflection::~GeneratedMessageReflection() {} +namespace { +UnknownFieldSet* empty_unknown_field_set_ = NULL; +GOOGLE_PROTOBUF_DECLARE_ONCE(empty_unknown_field_set_once_); + +void InitEmptyUnknownFieldSet() { + empty_unknown_field_set_ = new UnknownFieldSet; +} + +const UnknownFieldSet& GetEmptyUnknownFieldSet() { + ::google::protobuf::GoogleOnceInit(&empty_unknown_field_set_once_, &InitEmptyUnknownFieldSet); + return *empty_unknown_field_set_; +} +} // namespace + const UnknownFieldSet& GeneratedMessageReflection::GetUnknownFields( const Message& message) const { + if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + return GetEmptyUnknownFieldSet(); + } + if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) { + return GetInternalMetadataWithArena(message).unknown_fields(); + } const void* ptr = reinterpret_cast(&message) + unknown_fields_offset_; return *reinterpret_cast(ptr); } + UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields( Message* message) const { + if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) { + return MutableInternalMetadataWithArena(message)-> + mutable_unknown_fields(); + } void* ptr = reinterpret_cast(message) + unknown_fields_offset_; return reinterpret_cast(ptr); } @@ -303,12 +345,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { - const string* ptr = GetField(message, field); - // Initially, the string points to the default value stored in // the prototype. Only count the string if it has been changed // from the default value. - const string* default_ptr = DefaultRaw(field); + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + const string* ptr = + &GetField(message, field).Get(default_ptr); if (ptr != default_ptr) { // string fields are represented by just a pointer, so also @@ -363,8 +406,9 @@ void GeneratedMessageReflection::SwapField( case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_MESSAGE: - MutableRaw(message1, field)->Swap( - MutableRaw(message2, field)); + MutableRaw(message1, field)-> + Swap >( + MutableRaw(message2, field)); break; default: @@ -396,8 +440,8 @@ void GeneratedMessageReflection::SwapField( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: - std::swap(*MutableRaw(message1, field), - *MutableRaw(message2, field)); + MutableRaw(message1, field)->Swap( + MutableRaw(message2, field)); break; } break; @@ -549,12 +593,29 @@ void GeneratedMessageReflection::Swap( << "\"). Note that the exact same class is required; not just the same " "descriptor."; - uint32* has_bits1 = MutableHasBits(message1); - uint32* has_bits2 = MutableHasBits(message2); - int has_bits_size = (descriptor_->field_count() + 31) / 32; + // Check that both messages are in the same arena (or both on the heap). We + // need to copy all data if not, due to ownership semantics. + if (GetArena(message1) != GetArena(message2)) { + // Slow copy path. + // Use our arena as temp space, if available. + Message* temp = message1->New(GetArena(message1)); + temp->MergeFrom(*message1); + message1->CopyFrom(*message2); + message2->CopyFrom(*temp); + if (GetArena(message1) == NULL) { + delete temp; + } + return; + } + + if (has_bits_offset_ != -1) { + uint32* has_bits1 = MutableHasBits(message1); + uint32* has_bits2 = MutableHasBits(message2); + int has_bits_size = (descriptor_->field_count() + 31) / 32; - for (int i = 0; i < has_bits_size; i++) { - std::swap(has_bits1[i], has_bits2[i]); + for (int i = 0; i < has_bits_size; i++) { + std::swap(has_bits1[i], has_bits2[i]); + } } for (int i = 0; i < descriptor_->field_count(); i++) { @@ -715,17 +776,13 @@ void GeneratedMessageReflection::ClearField( case FieldDescriptor::CPPTYPE_STRING: { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. - case FieldOptions::STRING: - const string* default_ptr = DefaultRaw(field); - string** value = MutableRaw(message, field); - if (*value != default_ptr) { - if (field->has_default_value()) { - (*value)->assign(field->default_value_string()); - } else { - (*value)->clear(); - } - } + case FieldOptions::STRING: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + MutableRaw(message, field)->Destroy(default_ptr, + GetArena(message)); break; + } } break; } @@ -994,8 +1051,11 @@ string GeneratedMessageReflection::GetString( } else { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. - case FieldOptions::STRING: - return *GetField(message, field); + case FieldOptions::STRING: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + return GetField(message, field).Get(default_ptr); + } } GOOGLE_LOG(FATAL) << "Can't get here."; @@ -1013,8 +1073,11 @@ const string& GeneratedMessageReflection::GetStringReference( } else { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. - case FieldOptions::STRING: - return *GetField(message, field); + case FieldOptions::STRING: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + return GetField(message, field).Get(default_ptr); + } } GOOGLE_LOG(FATAL) << "Can't get here."; @@ -1034,16 +1097,15 @@ void GeneratedMessageReflection::SetString( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); if (field->containing_oneof() && !HasOneofField(*message, field)) { ClearOneof(message, field->containing_oneof()); - *MutableField(message, field) = new string; - } - string** ptr = MutableField(message, field); - if (*ptr == DefaultRaw(field)) { - *ptr = new string(value); - } else { - (*ptr)->assign(value); + MutableField(message, field)->UnsafeSetDefault( + default_ptr); } + MutableField(message, field)->Set(default_ptr, + value, GetArena(message)); break; } } @@ -1125,42 +1187,80 @@ void GeneratedMessageReflection::AddString( // ------------------------------------------------------------------- +inline bool CreateUnknownEnumValues(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + const EnumValueDescriptor* GeneratedMessageReflection::GetEnum( const Message& message, const FieldDescriptor* field) const { - USAGE_CHECK_ALL(GetEnum, SINGULAR, ENUM); + // Usage checked by GetEnumValue. + int value = GetEnumValue(message, field); + return field->enum_type()->FindValueByNumberCreatingIfUnknown(value); +} + +int GeneratedMessageReflection::GetEnumValue( + const Message& message, const FieldDescriptor* field) const { + USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM); - int value; + int32 value; if (field->is_extension()) { value = GetExtensionSet(message).GetEnum( field->number(), field->default_value_enum()->number()); } else { value = GetField(message, field); } - const EnumValueDescriptor* result = - field->enum_type()->FindValueByNumber(value); - GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field " - << field->full_name() << " of type " - << field->enum_type()->full_name() << "."; - return result; + return value; } void GeneratedMessageReflection::SetEnum( Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const { - USAGE_CHECK_ALL(SetEnum, SINGULAR, ENUM); + // Usage checked by SetEnumValue. USAGE_CHECK_ENUM_VALUE(SetEnum); + SetEnumValueInternal(message, field, value->number()); +} + +void GeneratedMessageReflection::SetEnumValue( + Message* message, const FieldDescriptor* field, + int value) const { + USAGE_CHECK_ALL(SetEnumValue, SINGULAR, ENUM); + if (!CreateUnknownEnumValues(descriptor_->file())) { + // Check that the value is valid if we don't support direct storage of + // unknown enum values. + const EnumValueDescriptor* value_desc = + field->enum_type()->FindValueByNumber(value); + if (value_desc == NULL) { + GOOGLE_LOG(DFATAL) << "SetEnumValue accepts only valid integer values: value " + << value << " unexpected for field " << field->full_name(); + // In production builds, DFATAL will not terminate the program, so we have + // to do something reasonable: just set the default value. + value = field->default_value_enum()->number(); + } + } + SetEnumValueInternal(message, field, value); +} +void GeneratedMessageReflection::SetEnumValueInternal( + Message* message, const FieldDescriptor* field, + int value) const { if (field->is_extension()) { MutableExtensionSet(message)->SetEnum(field->number(), field->type(), - value->number(), field); + value, field); } else { - SetField(message, field, value->number()); + SetField(message, field, value); } } const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum( const Message& message, const FieldDescriptor* field, int index) const { - USAGE_CHECK_ALL(GetRepeatedEnum, REPEATED, ENUM); + // Usage checked by GetRepeatedEnumValue. + int value = GetRepeatedEnumValue(message, field, index); + return field->enum_type()->FindValueByNumberCreatingIfUnknown(value); +} + +int GeneratedMessageReflection::GetRepeatedEnumValue( + const Message& message, const FieldDescriptor* field, int index) const { + USAGE_CHECK_ALL(GetRepeatedEnumValue, REPEATED, ENUM); int value; if (field->is_extension()) { @@ -1168,41 +1268,89 @@ const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum( } else { value = GetRepeatedField(message, field, index); } - const EnumValueDescriptor* result = - field->enum_type()->FindValueByNumber(value); - GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field " - << field->full_name() << " of type " - << field->enum_type()->full_name() << "."; - return result; + return value; } void GeneratedMessageReflection::SetRepeatedEnum( Message* message, const FieldDescriptor* field, int index, const EnumValueDescriptor* value) const { - USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM); + // Usage checked by SetRepeatedEnumValue. USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum); + SetRepeatedEnumValueInternal(message, field, index, value->number()); +} +void GeneratedMessageReflection::SetRepeatedEnumValue( + Message* message, + const FieldDescriptor* field, int index, + int value) const { + USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM); + if (!CreateUnknownEnumValues(descriptor_->file())) { + // Check that the value is valid if we don't support direct storage of + // unknown enum values. + const EnumValueDescriptor* value_desc = + field->enum_type()->FindValueByNumber(value); + if (value_desc == NULL) { + GOOGLE_LOG(DFATAL) << "SetRepeatedEnumValue accepts only valid integer values: " + << "value " << value << " unexpected for field " + << field->full_name(); + // In production builds, DFATAL will not terminate the program, so we have + // to do something reasonable: just set the default value. + value = field->default_value_enum()->number(); + } + } + SetRepeatedEnumValueInternal(message, field, index, value); +} + +void GeneratedMessageReflection::SetRepeatedEnumValueInternal( + Message* message, + const FieldDescriptor* field, int index, + int value) const { if (field->is_extension()) { MutableExtensionSet(message)->SetRepeatedEnum( - field->number(), index, value->number()); + field->number(), index, value); } else { - SetRepeatedField(message, field, index, value->number()); + SetRepeatedField(message, field, index, value); } } void GeneratedMessageReflection::AddEnum( Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const { - USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM); + // Usage checked by AddEnumValue. USAGE_CHECK_ENUM_VALUE(AddEnum); + AddEnumValueInternal(message, field, value->number()); +} +void GeneratedMessageReflection::AddEnumValue( + Message* message, const FieldDescriptor* field, + int value) const { + USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM); + if (!CreateUnknownEnumValues(descriptor_->file())) { + // Check that the value is valid if we don't support direct storage of + // unknown enum values. + const EnumValueDescriptor* value_desc = + field->enum_type()->FindValueByNumber(value); + if (value_desc == NULL) { + GOOGLE_LOG(DFATAL) << "AddEnumValue accepts only valid integer values: value " + << value << " unexpected for field " << field->full_name(); + // In production builds, DFATAL will not terminate the program, so we have + // to do something reasonable: just set the default value. + value = field->default_value_enum()->number(); + } + } + AddEnumValueInternal(message, field, value); +} + +void GeneratedMessageReflection::AddEnumValueInternal( + Message* message, const FieldDescriptor* field, + int value) const { if (field->is_extension()) { MutableExtensionSet(message)->AddEnum(field->number(), field->type(), field->options().packed(), - value->number(), field); + value, field); } else { - AddField(message, field, value->number()); + AddField(message, field, value); } } @@ -1246,7 +1394,7 @@ Message* GeneratedMessageReflection::MutableMessage( ClearOneof(message, field->containing_oneof()); result_holder = MutableField(message, field); const Message* default_message = DefaultRaw(field); - *result_holder = default_message->New(); + *result_holder = default_message->New(message->GetArena()); } } else { SetBit(message, field); @@ -1254,14 +1402,14 @@ Message* GeneratedMessageReflection::MutableMessage( if (*result_holder == NULL) { const Message* default_message = DefaultRaw(field); - *result_holder = default_message->New(); + *result_holder = default_message->New(message->GetArena()); } result = *result_holder; return result; } } -void GeneratedMessageReflection::SetAllocatedMessage( +void GeneratedMessageReflection::UnsafeArenaSetAllocatedMessage( Message* message, Message* sub_message, const FieldDescriptor* field) const { @@ -1288,12 +1436,42 @@ void GeneratedMessageReflection::SetAllocatedMessage( SetBit(message, field); } Message** sub_message_holder = MutableRaw(message, field); - delete *sub_message_holder; + if (GetArena(message) == NULL) { + delete *sub_message_holder; + } *sub_message_holder = sub_message; } } -Message* GeneratedMessageReflection::ReleaseMessage( +void GeneratedMessageReflection::SetAllocatedMessage( + Message* message, + Message* sub_message, + const FieldDescriptor* field) const { + // If message and sub-message are in different memory ownership domains + // (different arenas, or one is on heap and one is not), then we may need to + // do a copy. + if (sub_message != NULL && + sub_message->GetArena() != message->GetArena()) { + if (sub_message->GetArena() == NULL && message->GetArena() != NULL) { + // Case 1: parent is on an arena and child is heap-allocated. We can add + // the child to the arena's Own() list to free on arena destruction, then + // set our pointer. + message->GetArena()->Own(sub_message); + UnsafeArenaSetAllocatedMessage(message, sub_message, field); + } else { + // Case 2: all other cases. We need to make a copy. MutableMessage() will + // either get the existing message object, or instantiate a new one as + // appropriate w.r.t. our arena. + Message* sub_message_copy = MutableMessage(message, field); + sub_message_copy->CopyFrom(*sub_message); + } + } else { + // Same memory ownership domains. + UnsafeArenaSetAllocatedMessage(message, sub_message, field); + } +} + +Message* GeneratedMessageReflection::UnsafeArenaReleaseMessage( Message* message, const FieldDescriptor* field, MessageFactory* factory) const { @@ -1320,6 +1498,19 @@ Message* GeneratedMessageReflection::ReleaseMessage( } } +Message* GeneratedMessageReflection::ReleaseMessage( + Message* message, + const FieldDescriptor* field, + MessageFactory* factory) const { + Message* released = UnsafeArenaReleaseMessage(message, field, factory); + if (GetArena(message) != NULL && released != NULL) { + Message* copy_from_arena = released->New(); + copy_from_arena->CopyFrom(*released); + released = copy_from_arena; + } + return released; +} + const Message& GeneratedMessageReflection::GetRepeatedMessage( const Message& message, const FieldDescriptor* field, int index) const { USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE); @@ -1371,8 +1562,11 @@ Message* GeneratedMessageReflection::AddMessage( } else { prototype = &repeated->Get >(0); } - result = prototype->New(); - repeated->AddAllocated >(result); + result = prototype->New(message->GetArena()); + // We can guarantee here that repeated and result are either both heap + // allocated or arena owned. So it is safe to call the unsafe version + // of AddAllocated. + repeated->UnsafeArenaAddAllocated >(result); } return result; } @@ -1445,6 +1639,10 @@ const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByNumber( return descriptor_pool_->FindExtensionByNumber(descriptor_, number); } +bool GeneratedMessageReflection::SupportsUnknownEnumValues() const { + return CreateUnknownEnumValues(descriptor_->file()); +} + // =================================================================== // Some private helpers. @@ -1487,11 +1685,17 @@ inline const Type& GeneratedMessageReflection::DefaultRaw( inline const uint32* GeneratedMessageReflection::GetHasBits( const Message& message) const { + if (has_bits_offset_ == -1) { // proto3 with no has-bits. + return NULL; + } const void* ptr = reinterpret_cast(&message) + has_bits_offset_; return reinterpret_cast(ptr); } inline uint32* GeneratedMessageReflection::MutableHasBits( Message* message) const { + if (has_bits_offset_ == -1) { + return NULL; + } void* ptr = reinterpret_cast(message) + has_bits_offset_; return reinterpret_cast(ptr); } @@ -1525,25 +1729,113 @@ inline ExtensionSet* GeneratedMessageReflection::MutableExtensionSet( return reinterpret_cast(ptr); } +inline Arena* GeneratedMessageReflection::GetArena(Message* message) const { + if (arena_offset_ == kNoArenaPointer) { + return NULL; + } + + if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) { + // zero-overhead arena pointer overloading UnknownFields + return GetInternalMetadataWithArena(*message).arena(); + } + + // Baseline case: message class has a dedicated arena pointer. + void* ptr = reinterpret_cast(message) + arena_offset_; + return *reinterpret_cast(ptr); +} + +inline const InternalMetadataWithArena& +GeneratedMessageReflection::GetInternalMetadataWithArena( + const Message& message) const { + const void* ptr = reinterpret_cast(&message) + arena_offset_; + return *reinterpret_cast(ptr); +} + +inline InternalMetadataWithArena* +GeneratedMessageReflection::MutableInternalMetadataWithArena( + Message* message) const { + void* ptr = reinterpret_cast(message) + arena_offset_; + return reinterpret_cast(ptr); +} + // Simple accessors for manipulating has_bits_. inline bool GeneratedMessageReflection::HasBit( const Message& message, const FieldDescriptor* field) const { + if (has_bits_offset_ == -1) { + // 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(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 + // field must be a scalar. + + // Scalar primitive (numeric or string/bytes) fields are present if + // their value is non-zero (numeric) or non-empty (string/bytes). N.B.: + // we must use this definition here, rather than the "scalar fields + // always present" in the proto3 docs, because MergeFrom() semantics + // require presence as "present on wire", and reflection-based merge + // (which uses HasField()) needs to be consistent with this. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + return GetField(message, field).Get( + default_ptr).size() > 0; + } + } + return false; + case FieldDescriptor::CPPTYPE_BOOL: + return GetRaw(message, field) != false; + case FieldDescriptor::CPPTYPE_INT32: + return GetRaw(message, field) != 0; + case FieldDescriptor::CPPTYPE_INT64: + return GetRaw(message, field) != 0; + case FieldDescriptor::CPPTYPE_UINT32: + return GetRaw(message, field) != 0; + case FieldDescriptor::CPPTYPE_UINT64: + return GetRaw(message, field) != 0; + case FieldDescriptor::CPPTYPE_FLOAT: + return GetRaw(message, field) != 0.0; + case FieldDescriptor::CPPTYPE_DOUBLE: + return GetRaw(message, field) != 0.0; + case FieldDescriptor::CPPTYPE_ENUM: + return GetRaw(message, field) != 0; + case FieldDescriptor::CPPTYPE_MESSAGE: + // handled above; avoid warning + GOOGLE_LOG(FATAL) << "Reached impossible case in HasBit()."; + break; + } + } + } return GetHasBits(message)[field->index() / 32] & (1 << (field->index() % 32)); } inline void GeneratedMessageReflection::SetBit( Message* message, const FieldDescriptor* field) const { + if (has_bits_offset_ == -1) { + return; + } MutableHasBits(message)[field->index() / 32] |= (1 << (field->index() % 32)); } inline void GeneratedMessageReflection::ClearBit( Message* message, const FieldDescriptor* field) const { + if (has_bits_offset_ == -1) { + return; + } MutableHasBits(message)[field->index() / 32] &= ~(1 << (field->index() % 32)); } inline void GeneratedMessageReflection::SwapBit( Message* message1, Message* message2, const FieldDescriptor* field) const { + if (has_bits_offset_ == -1) { + return; + } bool temp_has_bit = HasBit(*message1, field); if (HasBit(*message2, field)) { SetBit(message1, field); @@ -1591,9 +1883,13 @@ inline void GeneratedMessageReflection::ClearOneof( case FieldDescriptor::CPPTYPE_STRING: { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. - case FieldOptions::STRING: - delete *MutableRaw(message, field); + case FieldOptions::STRING: { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + MutableField(message, field)-> + Destroy(default_ptr, GetArena(message)); break; + } } break; } @@ -1678,6 +1974,32 @@ inline Type* GeneratedMessageReflection::AddField( return repeated->Add(); } +MessageFactory* GeneratedMessageReflection::GetMessageFactory() const { + return message_factory_; +} + +void* GeneratedMessageReflection::RepeatedFieldData( + Message* message, const FieldDescriptor* field, + FieldDescriptor::CppType cpp_type, + const Descriptor* message_type) const { + GOOGLE_CHECK(field->is_repeated()); + GOOGLE_CHECK(field->cpp_type() == cpp_type || + (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && + cpp_type == FieldDescriptor::CPPTYPE_INT32)) + << "The type parameter T in RepeatedFieldRef API doesn't match " + << "the actual field type (for enums T should be the generated enum " + << "type or int32)."; + if (message_type != NULL) { + GOOGLE_CHECK_EQ(message_type, field->message_type()); + } + if (field->is_extension()) { + return MutableExtensionSet(message)->MutableRawRepeatedField( + field->number(), field->type(), field->is_packed(), field); + } else { + return reinterpret_cast(message) + offsets_[field->index()]; + } +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index b6671ad0..afdfd435 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -45,6 +45,7 @@ // is released to components. #include #include +#include #include @@ -134,7 +135,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int extensions_offset, const DescriptorPool* pool, MessageFactory* factory, - int object_size); + int object_size, + int arena_offset); // Similar with the construction above. Call this construction if the // message has oneof definition. @@ -170,7 +172,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int oneof_case_offset, const DescriptorPool* pool, MessageFactory* factory, - int object_size); + int object_size, + int arena_offset); ~GeneratedMessageReflection(); // implements Reflection ------------------------------------------- @@ -217,6 +220,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { string* scratch) const; const EnumValueDescriptor* GetEnum(const Message& message, const FieldDescriptor* field) const; + int GetEnumValue(const Message& message, + const FieldDescriptor* field) const; const Message& GetMessage(const Message& message, const FieldDescriptor* field, MessageFactory* factory = NULL) const; @@ -245,6 +250,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const string& value) const; void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; + void SetEnumValue(Message* message, const FieldDescriptor* field, + int value) const; Message* MutableMessage(Message* message, const FieldDescriptor* field, MessageFactory* factory = NULL) const; void SetAllocatedMessage(Message* message, @@ -275,6 +282,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const EnumValueDescriptor* GetRepeatedEnum(const Message& message, const FieldDescriptor* field, int index) const; + int GetRepeatedEnumValue(const Message& message, + const FieldDescriptor* field, + int index) const; const Message& GetRepeatedMessage(const Message& message, const FieldDescriptor* field, int index) const; @@ -299,6 +309,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const string& value) const; void SetRepeatedEnum(Message* message, const FieldDescriptor* field, int index, const EnumValueDescriptor* value) const; + void SetRepeatedEnumValue(Message* message, const FieldDescriptor* field, + int index, int value) const; // Get a mutable pointer to a field with a message type. Message* MutableRepeatedMessage(Message* message, const FieldDescriptor* field, @@ -323,17 +335,42 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { void AddEnum(Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; + void AddEnumValue(Message* message, + const FieldDescriptor* field, + int value) const; Message* AddMessage(Message* message, const FieldDescriptor* field, MessageFactory* factory = NULL) const; const FieldDescriptor* FindKnownExtensionByName(const string& name) const; const FieldDescriptor* FindKnownExtensionByNumber(int number) const; + bool SupportsUnknownEnumValues() const; + + // This value for arena_offset_ indicates that there is no arena pointer in + // this message (e.g., old generated code). + static const int kNoArenaPointer = -1; + + // This value for unknown_field_offset_ indicates that there is no + // UnknownFieldSet in this message, and that instead, we are using the + // Zero-Overhead Arena Pointer trick. When this is the case, arena_offset_ + // actually indexes to an InternalMetadataWithArena instance, which can return + // either an arena pointer or an UnknownFieldSet or both. It is never the case + // that unknown_field_offset_ == kUnknownFieldSetInMetadata && arena_offset_ + // == kNoArenaPointer. + static const int kUnknownFieldSetInMetadata = -1; + protected: virtual void* MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, int ctype, const Descriptor* desc) const; + virtual MessageFactory* GetMessageFactory() const; + + virtual void* RepeatedFieldData( + Message* message, const FieldDescriptor* field, + FieldDescriptor::CppType cpp_type, + const Descriptor* message_type) const; + private: friend class GeneratedMessage; @@ -350,6 +387,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int oneof_case_offset_; int unknown_fields_offset_; int extensions_offset_; + int arena_offset_; int object_size_; const DescriptorPool* descriptor_pool_; @@ -376,6 +414,11 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const OneofDescriptor* oneof_descriptor) const; inline const ExtensionSet& GetExtensionSet(const Message& message) const; inline ExtensionSet* MutableExtensionSet(Message* message) const; + inline Arena* GetArena(Message* message) const; + inline const internal::InternalMetadataWithArena& + GetInternalMetadataWithArena(const Message& message) const; + inline internal::InternalMetadataWithArena* + MutableInternalMetadataWithArena(Message* message) const; inline bool HasBit(const Message& message, const FieldDescriptor* field) const; @@ -438,6 +481,28 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int GetExtensionNumberOrDie(const Descriptor* type) const; + // Internal versions of EnumValue API perform no checking. Called after checks + // by public methods. + void SetEnumValueInternal(Message* message, + const FieldDescriptor* field, + int value) const; + void SetRepeatedEnumValueInternal(Message* message, + const FieldDescriptor* field, + int index, + int value) const; + void AddEnumValueInternal(Message* message, + const FieldDescriptor* field, + int value) const; + + + Message* UnsafeArenaReleaseMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + void UnsafeArenaSetAllocatedMessage(Message* message, + Message* sub_message, + const FieldDescriptor* field) const; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection); }; diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 53449755..df88205c 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -40,8 +40,10 @@ #include #include +#include #include #include +#include #include #include @@ -149,6 +151,19 @@ void CodedInputStream::PopLimit(Limit limit) { legitimate_message_end_ = false; } +std::pair +CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) { + return make_pair(PushLimit(byte_limit), --recursion_budget_); +} + +bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) { + bool result = ConsumedEntireMessage(); + PopLimit(limit); + GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_); + ++recursion_budget_; + return result; +} + int CodedInputStream::BytesUntilLimit() const { if (current_limit_ == INT_MAX) return -1; int current_position = CurrentPosition(); diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 775c6067..b9c30fa3 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -110,6 +110,7 @@ #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ #include +#include #ifdef _MSC_VER #if defined(_M_IX86) && \ !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) @@ -129,8 +130,8 @@ #endif #include - namespace google { + namespace protobuf { class DescriptorPool; @@ -388,6 +389,23 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Decrements the recursion depth. void DecrementRecursionDepth(); + // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_). + // Using this can reduce code size and complexity in some cases. The caller + // is expected to check that the second part of the result is non-negative (to + // bail out if the depth of recursion is too high) and, if all is well, to + // later pass the first part of the result to PopLimit() or similar. + std::pair IncrementRecursionDepthAndPushLimit( + int byte_limit); + + // Helper that is equivalent to: { + // bool result = ConsumedEntireMessage(); + // PopLimit(limit); + // DecrementRecursionDepth(); + // return result; } + // Using this can reduce code size and complexity in some cases. + // Do not use unless the current recursion depth is greater than zero. + bool DecrementRecursionDepthAndPopLimit(Limit limit); + // Extension Registry ---------------------------------------------- // ADVANCED USAGE: 99.9% of people can ignore this section. // @@ -470,9 +488,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream { private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); - ZeroCopyInputStream* input_; const uint8* buffer_; const uint8* buffer_end_; // pointer to the end of the buffer. + ZeroCopyInputStream* input_; int total_bytes_read_; // total bytes read from input_, including // the current buffer @@ -513,9 +531,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // If -2: Internal: Limit has been reached, print full size when destructing. int total_bytes_warning_threshold_; - // Current recursion depth, controlled by IncrementRecursionDepth() and - // DecrementRecursionDepth(). - int recursion_depth_; + // Current recursion budget, controlled by IncrementRecursionDepth() and + // similar. Starts at recursion_limit_ and goes down: if this reaches + // -1 we are over budget. + int recursion_budget_; // Recursion depth limit, set by SetRecursionLimit(). int recursion_limit_; @@ -1132,16 +1151,17 @@ inline void CodedOutputStream::Advance(int amount) { } inline void CodedInputStream::SetRecursionLimit(int limit) { + recursion_budget_ += limit - recursion_limit_; recursion_limit_ = limit; } inline bool CodedInputStream::IncrementRecursionDepth() { - ++recursion_depth_; - return recursion_depth_ <= recursion_limit_; + --recursion_budget_; + return recursion_budget_ >= 0; } inline void CodedInputStream::DecrementRecursionDepth() { - if (recursion_depth_ > 0) --recursion_depth_; + if (recursion_budget_ < recursion_limit_) ++recursion_budget_; } inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool, @@ -1163,9 +1183,9 @@ inline int CodedInputStream::BufferSize() const { } inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) - : input_(input), - buffer_(NULL), + : buffer_(NULL), buffer_end_(NULL), + input_(input), total_bytes_read_(0), overflow_bytes_(0), last_tag_(0), @@ -1175,7 +1195,7 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) buffer_size_after_limit_(0), total_bytes_limit_(kDefaultTotalBytesLimit), total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), + recursion_budget_(default_recursion_limit_), recursion_limit_(default_recursion_limit_), extension_pool_(NULL), extension_factory_(NULL) { @@ -1184,9 +1204,9 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) } inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) - : input_(NULL), - buffer_(buffer), + : buffer_(buffer), buffer_end_(buffer + size), + input_(NULL), total_bytes_read_(size), overflow_bytes_(0), last_tag_(0), @@ -1196,7 +1216,7 @@ inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) buffer_size_after_limit_(0), total_bytes_limit_(kDefaultTotalBytesLimit), total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), + recursion_budget_(default_recursion_limit_), recursion_limit_(default_recursion_limit_), extension_pool_(NULL), extension_factory_(NULL) { diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h index 88c14cab..cd8d1746 100644 --- a/src/google/protobuf/io/coded_stream_inl.h +++ b/src/google/protobuf/io/coded_stream_inl.h @@ -36,6 +36,7 @@ #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ #define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ +#include #include #include #include @@ -51,10 +52,12 @@ inline bool CodedInputStream::InternalReadStringInline(string* buffer, if (BufferSize() >= size) { STLStringResizeUninitialized(buffer, size); - // When buffer is empty, string_as_array(buffer) will return NULL but memcpy - // requires non-NULL pointers even when size is 0. Hench this check. - if (size > 0) { - memcpy(mutable_string_data(buffer), buffer_, size); + std::pair z = as_string_data(buffer); + if (z.second) { + // Oddly enough, memcpy() requires its first two args to be non-NULL even + // if we copy 0 bytes. So, we have ensured that z.first is non-NULL here. + GOOGLE_DCHECK(z.first != NULL); + memcpy(z.first, buffer_, size); Advance(size); } return true; diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index f4cb5ea1..bbe5e399 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -144,6 +144,7 @@ uint8 CodedStreamTest::buffer_[CodedStreamTest::kBufferSize]; // checks. const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024}; + // ------------------------------------------------------------------- // Varint tests. diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc index ee286961..e6037863 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -48,7 +48,7 @@ static const int kDefaultBufferSize = 65536; GzipInputStream::GzipInputStream( ZeroCopyInputStream* sub_stream, Format format, int buffer_size) - : format_(format), sub_stream_(sub_stream), zerror_(Z_OK) { + : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) { zcontext_.zalloc = Z_NULL; zcontext_.zfree = Z_NULL; zcontext_.opaque = Z_NULL; @@ -134,6 +134,7 @@ bool GzipInputStream::Next(const void** data, int* size) { if (zcontext_.next_out != NULL) { // sub_stream_ may have concatenated streams to follow zerror_ = inflateEnd(&zcontext_); + byte_count_ += zcontext_.total_out; if (zerror_ != Z_OK) { return false; } @@ -178,8 +179,12 @@ bool GzipInputStream::Skip(int count) { return ok; } int64 GzipInputStream::ByteCount() const { - return zcontext_.total_out + - (((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_)); + int64 ret = byte_count_ + zcontext_.total_out; + if (zcontext_.next_out != NULL && output_position_ != NULL) { + ret += reinterpret_cast(zcontext_.next_out) - + reinterpret_cast(output_position_); + } + return ret; } // ========================================================================= diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h index c7ccc260..82445000 100644 --- a/src/google/protobuf/io/gzip_stream.h +++ b/src/google/protobuf/io/gzip_stream.h @@ -99,6 +99,7 @@ class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream { void* output_buffer_; void* output_position_; size_t output_buffer_length_; + int64 byte_count_; int Inflate(int flush); void DoNextOutput(const void** data, int* size); diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index c8df4177..e621ba1d 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -142,6 +142,19 @@ void Printer::Print(const char* text, Print(vars, text); } +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + vars[variable4] = value4; + Print(vars, text); +} + void Printer::Indent() { indent_ += " "; } diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index f06cbf2f..92ce3409 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -86,6 +86,11 @@ class LIBPROTOBUF_EXPORT Printer { void Print(const char* text, const char* variable1, const string& value1, const char* variable2, const string& value2, const char* variable3, const string& value3); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4); // TODO(kenton): Overloaded versions with more variables? Three seems // to be enough. diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 58aff0e2..97b73b88 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index e18da72c..a517161d 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -334,6 +334,18 @@ class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStrea // =================================================================== +// mutable_string_data() and as_string_data() are workarounds to improve +// the performance of writing new data to an existing string. Unfortunately +// the methods provided by the string class are suboptimal, and using memcpy() +// is mildly annoying because it requires its pointer args to be non-NULL even +// if we ask it to copy 0 bytes. Furthermore, string_as_array() has the +// property that it always returns NULL if its arg is the empty string, exactly +// what we want to avoid if we're using it in conjunction with memcpy()! +// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size), +// where s is a string*. Without C++11, &(*s)[0] is not guaranteed to be safe, +// so we use string_as_array(), and live with the extra logic that tests whether +// *s is empty. + // Return a pointer to mutable characters underlying the given string. The // return value is valid until the next time the string is resized. We // trust the caller to treat the return value as an array of length s->size(). @@ -347,6 +359,19 @@ inline char* mutable_string_data(string* s) { #endif } +// as_string_data(s) is equivalent to +// ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); }) +// Sometimes it's faster: in some scenarios p cannot be NULL, and then the +// code can avoid that check. +inline std::pair as_string_data(string* s) { + char *p = mutable_string_data(s); +#ifdef LANG_CXX11 + return make_pair(p, true); +#else + return make_pair(p, p != NULL); +#endif +} + } // namespace io } // namespace protobuf diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index bf978cc8..dd3d1285 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -656,6 +656,43 @@ TEST_F(IoTest, TwoSessionWriteGzip) { delete [] temp_buffer; delete [] buffer; } + +TEST_F(IoTest, GzipInputByteCountAfterClosed) { + string golden = "abcdefghijklmnopqrstuvwxyz"; + string compressed = Compress(golden, GzipOutputStream::Options()); + + for (int i = 0; i < kBlockSizeCount; i++) { + ArrayInputStream arr_input(compressed.data(), compressed.size(), + kBlockSizes[i]); + GzipInputStream gz_input(&arr_input); + const void* buffer; + int size; + while (gz_input.Next(&buffer, &size)) { + EXPECT_LE(gz_input.ByteCount(), golden.size()); + } + EXPECT_EQ(golden.size(), gz_input.ByteCount()); + } +} + +TEST_F(IoTest, GzipInputByteCountAfterClosedConcatenatedStreams) { + string golden1 = "abcdefghijklmnopqrstuvwxyz"; + string golden2 = "the quick brown fox jumps over the lazy dog"; + const size_t total_size = golden1.size() + golden2.size(); + string compressed = Compress(golden1, GzipOutputStream::Options()) + + Compress(golden2, GzipOutputStream::Options()); + + for (int i = 0; i < kBlockSizeCount; i++) { + ArrayInputStream arr_input(compressed.data(), compressed.size(), + kBlockSizes[i]); + GzipInputStream gz_input(&arr_input); + const void* buffer; + int size; + while (gz_input.Next(&buffer, &size)) { + EXPECT_LE(gz_input.ByteCount(), total_size); + } + EXPECT_EQ(total_size, gz_input.ByteCount()); + } +} #endif // There is no string input, only string output. Also, it doesn't support diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 1324ed9b..aab00fdf 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include #include +#include #include namespace google { @@ -222,6 +224,38 @@ void* Reflection::MutableRawRepeatedString( } +// Default EnumValue API implementations. Real reflection implementations should +// override these. However, there are several legacy implementations that do +// not, and cannot easily be changed at the same time as the Reflection API, so +// we provide these for now. +// TODO: Remove these once all Reflection implementations are updated. +int Reflection::GetEnumValue(const Message& message, + const FieldDescriptor* field) const { + GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; + return 0; +} +void Reflection::SetEnumValue(Message* message, + const FieldDescriptor* field, + int value) const { + GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; +} +int Reflection::GetRepeatedEnumValue( + const Message& message, + const FieldDescriptor* field, int index) const { + GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; + return 0; +} +void Reflection::SetRepeatedEnumValue(Message* message, + const FieldDescriptor* field, int index, + int value) const { + GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; +} +void Reflection::AddEnumValue(Message* message, + const FieldDescriptor* field, + int value) const { + GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; +} + // ============================================================================= // MessageFactory @@ -354,5 +388,60 @@ void MessageFactory::InternalRegisterGeneratedMessage( } +MessageFactory* Reflection::GetMessageFactory() const { + GOOGLE_LOG(FATAL) << "Not implemented."; + return NULL; +} + +void* Reflection::RepeatedFieldData( + Message* message, const FieldDescriptor* field, + FieldDescriptor::CppType cpp_type, + const Descriptor* message_type) const { + GOOGLE_LOG(FATAL) << "Not implemented."; + return NULL; +} + +namespace internal { +RepeatedFieldAccessor::~RepeatedFieldAccessor() { +} +} // namespace internal + +const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( + const FieldDescriptor* field) const { + GOOGLE_CHECK(field->is_repeated()); + switch (field->cpp_type()) { +#define HANDLE_PRIMITIVE_TYPE(TYPE, type) \ + case FieldDescriptor::CPPTYPE_ ## TYPE: \ + return internal::Singleton >::get(); + HANDLE_PRIMITIVE_TYPE(INT32, int32) + HANDLE_PRIMITIVE_TYPE(UINT32, uint32) + HANDLE_PRIMITIVE_TYPE(INT64, int64) + HANDLE_PRIMITIVE_TYPE(UINT64, uint64) + HANDLE_PRIMITIVE_TYPE(FLOAT, float) + HANDLE_PRIMITIVE_TYPE(DOUBLE, double) + HANDLE_PRIMITIVE_TYPE(BOOL, bool) + HANDLE_PRIMITIVE_TYPE(ENUM, int32) +#undef HANDLE_PRIMITIVE_TYPE + case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: + case FieldOptions::STRING: + return internal::Singleton::get(); + } + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + return internal::Singleton::get(); + } + GOOGLE_LOG(FATAL) << "Should not reach here."; + return NULL; +} + +namespace internal { +// Macro defined in repeated_field.h. We can only define the Message-specific +// GenericTypeHandler specializations here because we depend on Message, which +// is not part of proto2-lite hence is not available in repeated_field.h. +DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(Message); +} // namespace internal + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 67d45493..1d8f2499 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -112,8 +112,10 @@ #include #include +#include #include +#include #include #include @@ -121,6 +123,7 @@ #define GOOGLE_PROTOBUF_HAS_ONEOF +#define GOOGLE_PROTOBUF_HAS_ARENAS namespace google { namespace protobuf { @@ -174,6 +177,17 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // for return-type covariance.) virtual Message* New() const = 0; + // Construct a new instance on the arena. Ownership is passed to the caller + // if arena is a NULL. Default implementation allows for API compatibility + // during the Arena transition. + virtual Message* New(::google::protobuf::Arena* arena) const { + Message* message = New(); + if (arena != NULL) { + arena->Own(message); + } + return message; + } + // Make this message into a copy of the given message. The given message // must have the same descriptor, but need not necessarily be the same class. // By default this is just implemented as "Clear(); MergeFrom(from);". @@ -313,6 +327,20 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); }; +namespace internal { +// Forward-declare interfaces used to implement RepeatedFieldRef. +// These are protobuf internals that users shouldn't care about. +class RepeatedFieldAccessor; +} // namespace internal + +// Forward-declare RepeatedFieldRef templates. The second type parameter is +// used for SFINAE tricks. Users should ignore it. +template +class RepeatedFieldRef; + +template +class MutableRepeatedFieldRef; + // This interface contains methods that can be used to dynamically access // and modify the fields of a protocol message. Their semantics are // similar to the accessors the protocol compiler generates. @@ -361,12 +389,15 @@ class LIBPROTOBUF_EXPORT Reflection { // Get the UnknownFieldSet for the message. This contains fields which // were seen when the Message was parsed but were not recognized according - // to the Message's definition. + // to the Message's definition. For proto3 protos, this method will always + // return an empty UnknownFieldSet. virtual const UnknownFieldSet& GetUnknownFields( const Message& message) const = 0; // Get a mutable pointer to the UnknownFieldSet for the message. This // contains fields which were seen when the Message was parsed but were not - // recognized according to the Message's definition. + // recognized according to the Message's definition. For proto3 protos, this + // method will return a valid mutable UnknownFieldSet pointer but modifying + // it won't affect the serialized bytes of the message. virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0; // Estimate the amount of memory used by the message object. @@ -385,7 +416,7 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void ClearField(Message* message, const FieldDescriptor* field) const = 0; - // Check if the oneof is set. Returns ture if any field in oneof + // Check if the oneof is set. Returns true if any field in oneof // is set, false otherwise. // TODO(jieluo) - make it pure virtual after updating all // the subclasses. @@ -464,6 +495,15 @@ class LIBPROTOBUF_EXPORT Reflection { const FieldDescriptor* field) const = 0; virtual const EnumValueDescriptor* GetEnum( const Message& message, const FieldDescriptor* field) const = 0; + + // GetEnumValue() returns an enum field's value as an integer rather than + // an EnumValueDescriptor*. If the integer value does not correspond to a + // known value descriptor, a new value descriptor is created. (Such a value + // will only be present when the new unknown-enum-value semantics are enabled + // for a message.) + virtual int GetEnumValue( + const Message& message, const FieldDescriptor* field) const; + // See MutableMessage() for the meaning of the "factory" parameter. virtual const Message& GetMessage(const Message& message, const FieldDescriptor* field, @@ -512,6 +552,14 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; + // Set an enum field's value with an integer rather than EnumValueDescriptor. + // If the value does not correspond to a known enum value, either behavior is + // undefined (for proto2 messages), or the value is accepted silently for + // messages with new unknown-enum-value semantics. + virtual void SetEnumValue(Message* message, + const FieldDescriptor* field, + int value) const; + // Get a mutable pointer to a field with a message type. If a MessageFactory // is provided, it will be used to construct instances of the sub-message; // otherwise, the default factory is used. If the field is an extension that @@ -574,6 +622,14 @@ class LIBPROTOBUF_EXPORT Reflection { virtual const EnumValueDescriptor* GetRepeatedEnum( const Message& message, const FieldDescriptor* field, int index) const = 0; + // GetRepeatedEnumValue() returns an enum field's value as an integer rather + // than an EnumValueDescriptor*. If the integer value does not correspond to a + // known value descriptor, a new value descriptor is created. (Such a value + // will only be present when the new unknown-enum-value semantics are enabled + // for a message.) + virtual int GetRepeatedEnumValue( + const Message& message, + const FieldDescriptor* field, int index) const; virtual const Message& GetRepeatedMessage( const Message& message, const FieldDescriptor* field, int index) const = 0; @@ -614,6 +670,13 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void SetRepeatedEnum(Message* message, const FieldDescriptor* field, int index, const EnumValueDescriptor* value) const = 0; + // Set an enum field's value with an integer rather than EnumValueDescriptor. + // If the value does not correspond to a known enum value, either behavior is + // undefined (for proto2 messages), or the value is accepted silently for + // messages with new unknown-enum-value semantics. + virtual void SetRepeatedEnumValue(Message* message, + const FieldDescriptor* field, int index, + int value) const; // Get a mutable pointer to an element of a repeated field with a message // type. virtual Message* MutableRepeatedMessage( @@ -643,12 +706,57 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void AddEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; + // Set an enum field's value with an integer rather than EnumValueDescriptor. + // If the value does not correspond to a known enum value, either behavior is + // undefined (for proto2 messages), or the value is accepted silently for + // messages with new unknown-enum-value semantics. + virtual void AddEnumValue(Message* message, + const FieldDescriptor* field, + int value) const; // See MutableMessage() for comments on the "factory" parameter. virtual Message* AddMessage(Message* message, const FieldDescriptor* field, MessageFactory* factory = NULL) const = 0; + // Get a RepeatedFieldRef object that can be used to read the underlying + // repeated field. The type parameter T must be set according to the + // field's cpp type. The following table shows the mapping from cpp type + // to acceptable T. + // + // field->cpp_type() T + // CPPTYPE_INT32 int32 + // CPPTYPE_UINT32 uint32 + // CPPTYPE_INT64 int64 + // CPPTYPE_UINT64 uint64 + // CPPTYPE_DOUBLE double + // CPPTYPE_FLOAT float + // CPPTYPE_BOOL bool + // CPPTYPE_ENUM generated enum type or int32 + // CPPTYPE_STRING string + // CPPTYPE_MESSAGE generated message type or google::protobuf::Message + // + // A RepeatedFieldRef object can be copied and the resulted object will point + // to the same repeated field in the same message. The object can be used as + // long as the message is not destroyed. + // + // Note that to use this method users need to include the header file + // "google/protobuf/reflection.h" (which defines the RepeatedFieldRef + // class templates). + template + RepeatedFieldRef GetRepeatedFieldRef( + const Message& message, const FieldDescriptor* field) const; + + // Like GetRepeatedFieldRef() but return an object that can also be used + // manipulate the underlying repeated field. + template + MutableRepeatedFieldRef GetMutableRepeatedFieldRef( + Message* message, const FieldDescriptor* field) const; + + // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field + // access. The following repeated field accesors will be removed in the + // future. + // // Repeated field accessors ------------------------------------------------- // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular // access to the data in a RepeatedField. The methods below provide aggregate @@ -659,22 +767,30 @@ class LIBPROTOBUF_EXPORT Reflection { // // Usage example: my_doubs = refl->GetRepeatedField(msg, fd); + // DEPRECATED. Please use GetRepeatedFieldRef(). + // // for T = Cord and all protobuf scalar types except enums. template const RepeatedField& GetRepeatedField( const Message&, const FieldDescriptor*) const; + // DEPRECATED. Please use GetMutableRepeatedFieldRef(). + // // for T = Cord and all protobuf scalar types except enums. template RepeatedField* MutableRepeatedField( Message*, const FieldDescriptor*) const; + // DEPRECATED. Please use GetRepeatedFieldRef(). + // // for T = string, google::protobuf::internal::StringPieceField // google::protobuf::Message & descendants. template const RepeatedPtrField& GetRepeatedPtrField( const Message&, const FieldDescriptor*) const; + // DEPRECATED. Please use GetMutableRepeatedFieldRef(). + // // for T = string, google::protobuf::internal::StringPieceField // google::protobuf::Message & descendants. template @@ -693,6 +809,39 @@ class LIBPROTOBUF_EXPORT Reflection { virtual const FieldDescriptor* FindKnownExtensionByNumber( int number) const = 0; + // Feature Flags ------------------------------------------------------------- + + // Does this message support storing arbitrary integer values in enum fields? + // If |true|, GetEnumValue/SetEnumValue and associated repeated-field versions + // take arbitrary integer values, and the legacy GetEnum() getter will + // dynamically create an EnumValueDescriptor for any integer value without + // one. If |false|, setting an unknown enum value via the integer-based + // setters results in undefined behavior (in practice, GOOGLE_DCHECK-fails). + // + // Generic code that uses reflection to handle messages with enum fields + // should check this flag before using the integer-based setter, and either + // downgrade to a compatible value or use the UnknownFieldSet if not. For + // example: + // + // int new_value = GetValueFromApplicationLogic(); + // if (reflection->SupportsUnknownEnumValues()) { + // reflection->SetEnumValue(message, field, new_value); + // } else { + // if (field_descriptor->enum_type()-> + // FindValueByNumver(new_value) != NULL) { + // reflection->SetEnumValue(message, field, new_value); + // } else if (emit_unknown_enum_values) { + // reflection->MutableUnknownFields(message)->AddVarint( + // field->number(), + // new_value); + // } else { + // // convert value to a compatible/default value. + // new_value = CompatibleDowngrade(new_value); + // reflection->SetEnumValue(message, field, new_value); + // } + // } + virtual bool SupportsUnknownEnumValues() const { return false; } + // --------------------------------------------------------------------------- protected: @@ -705,7 +854,38 @@ class LIBPROTOBUF_EXPORT Reflection { Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, int ctype, const Descriptor* message_type) const = 0; + virtual MessageFactory* GetMessageFactory() const; + + // The following methods are used to implement (Mutable)RepeatedFieldRef. + // A Ref object will store a raw pointer to the repeated field data (obtained + // from RepeatedFieldData()) and a pointer to a Accessor (obtained from + // RepeatedFieldAccessor) which will be used to access the raw data. + // + // TODO(xiaofeng): Make these methods pure-virtual. + + // Returns a raw pointer to the repeated field + // + // "cpp_type" and "message_type" are decuded from the type parameter T passed + // to Get(Mutable)RepeatedFieldRef. If T is a generated message type, + // "message_type" should be set to its descriptor. Otherwise "message_type" + // should be set to NULL. Implementations of this method should check whether + // "cpp_type"/"message_type" is consistent with the actual type of the field. + virtual void* RepeatedFieldData( + Message* message, const FieldDescriptor* field, + FieldDescriptor::CppType cpp_type, + const Descriptor* message_type) const; + + // The returned pointer should point to a singleton instance which implements + // the RepeatedFieldAccessor interface. + virtual const internal::RepeatedFieldAccessor* RepeatedFieldAccessor( + const FieldDescriptor* field) const; + private: + template + friend class RepeatedFieldRef; + template + friend class MutableRepeatedFieldRef; + // Special version for specialized implementations of string. We can't call // MutableRawRepeatedField directly here because we don't have access to // FieldOptions::* which are defined in descriptor.pb.h. Including that @@ -859,7 +1039,6 @@ inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( FieldDescriptor::CPPTYPE_MESSAGE, -1, PB::default_instance().GetDescriptor())); } - } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 14cdc91f..63be0e9b 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -34,6 +34,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include #include #include #include @@ -153,6 +154,15 @@ bool InlineParsePartialFromArray(const void* data, int size, } // namespace + +MessageLite* MessageLite::New(::google::protobuf::Arena* arena) const { + MessageLite* message = New(); + if (arena != NULL) { + arena->Own(message); + } + return message; +} + bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) { return InlineMergeFromCodedStream(input, this); } @@ -233,6 +243,12 @@ bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const { bool MessageLite::SerializePartialToCodedStream( io::CodedOutputStream* output) const { const int size = ByteSize(); // Force size to be cached. + if (size < 0) { + // Messages >2G cannot be serialized due to overflow computing ByteSize. + GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?)."; + return false; + } + uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size); if (buffer != NULL) { uint8* end = SerializeWithCachedSizesToArray(buffer); @@ -277,6 +293,12 @@ bool MessageLite::AppendToString(string* output) const { bool MessageLite::AppendPartialToString(string* output) const { int old_size = output->size(); int byte_size = ByteSize(); + if (byte_size < 0) { + // Messages >2G cannot be serialized due to overflow computing ByteSize. + GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?)."; + return false; + } + STLStringResizeUninitialized(output, old_size + byte_size); uint8* start = reinterpret_cast(io::mutable_string_data(output) + old_size); diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 027cabf9..106982cc 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -43,7 +43,7 @@ namespace google { namespace protobuf { - + class Arena; namespace io { class CodedInputStream; class CodedOutputStream; @@ -88,6 +88,27 @@ class LIBPROTOBUF_EXPORT MessageLite { // caller. virtual MessageLite* New() const = 0; + // Construct a new instance on the arena. Ownership is passed to the caller + // if arena is a NULL. Default implementation for backwards compatibility. + virtual MessageLite* New(::google::protobuf::Arena* arena) const; + + // Get the arena, if any, associated with this message. Virtual method + // required for generic operations but most arena-related operations should + // use the GetArenaNoVirtual() generated-code method. Default implementation + // to reduce code size by avoiding the need for per-type implementations when + // types do not implement arena support. + virtual ::google::protobuf::Arena* GetArena() const { return NULL; } + + // Get a pointer that may be equal to this message's arena, or may not be. If + // the value returned by this method is equal to some arena pointer, then this + // message is on that arena; however, if this message is on some arena, this + // method may or may not return that arena's pointer. As a tradeoff, this + // method may be more efficient than GetArena(). The intent is to allow + // underlying representations that use e.g. tagged pointers to sometimes store + // the arena pointer directly, and sometimes in a more indirect way, and allow + // a fastpath comparison against the arena pointer when it's easy to obtain. + virtual void* GetMaybeArenaPointer() const { return GetArena(); } + // Clear all fields of the message and set them to their default values. // Clear() avoids freeing memory, assuming that any memory allocated // to hold parts of the message will be needed again to hold the next diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index a5f339f1..ebfb4321 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -242,6 +242,25 @@ TEST(MessageTest, CheckOverflow) { #endif // PROTOBUF_HAS_DEATH_TEST +namespace { + +class NegativeByteSize : public unittest::TestRequired { + public: + virtual int ByteSize() const { return -1; } +}; + +} // namespace + +TEST(MessageTest, SerializationFailsOnNegativeByteSize) { + NegativeByteSize message; + string string_output; + EXPECT_FALSE(message.AppendPartialToString(&string_output)); + + io::ArrayOutputStream coded_raw_output(NULL, 100); + io::CodedOutputStream coded_output(&coded_raw_output); + EXPECT_FALSE(message.SerializePartialToCodedStream(&coded_output)); +} + TEST(MessageTest, BypassInitializationCheckOnSerialize) { unittest::TestRequired message; io::ArrayOutputStream raw_output(NULL, 0); diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h new file mode 100644 index 00000000..30b2a6ee --- /dev/null +++ b/src/google/protobuf/metadata.h @@ -0,0 +1,164 @@ +// 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. + +// This header file defines an internal class that encapsulates internal message +// metadata (Unknown-field set, Arena pointer, ...) and allows its +// representation to be made more space-efficient via various optimizations. +// +// Note that this is distinct from google::protobuf::Metadata, which encapsulates +// Descriptor and Reflection pointers. + +#ifndef GOOGLE_PROTOBUF_METADATA_H__ +#define GOOGLE_PROTOBUF_METADATA_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +// This is the representation for messages that support arena allocation. It +// uses a tagged pointer to either store the Arena pointer, if there are no +// unknown fields, or a pointer to a block of memory with both the Arena pointer +// and the UnknownFieldSet, if there are unknown fields. This optimization +// allows for "zero-overhead" storage of the Arena pointer, relative to the +// above baseline implementation. +// +// The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to +// indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container +// pointer. +class LIBPROTOBUF_EXPORT InternalMetadataWithArena { + public: + InternalMetadataWithArena() : ptr_(NULL) {} + explicit InternalMetadataWithArena(Arena* arena) + : ptr_ (arena) {} + + ~InternalMetadataWithArena() { + if (have_unknown_fields() && arena() == NULL) { + delete PtrValue(); + } + ptr_ = NULL; + } + + inline const UnknownFieldSet& unknown_fields() const + GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { + return PtrValue()->unknown_fields_; + } else { + return *UnknownFieldSet::default_instance(); + } + } + + inline UnknownFieldSet* mutable_unknown_fields() GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) { + return &PtrValue()->unknown_fields_; + } else { + return mutable_unknown_fields_slow(); + } + } + + inline Arena* arena() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { + return PtrValue()->arena_; + } else { + return PtrValue(); + } + } + + inline bool have_unknown_fields() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + return PtrTag() == kTagContainer; + } + + inline void Swap(InternalMetadataWithArena* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + // Semantics here are that we swap only the unknown fields, not the arena + // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to + // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in + // different states (direct arena pointer vs. container with UFS) so we + // cannot simply swap ptr_ and then restore the arena pointers. We reuse + // UFS's swap implementation instead. + if (have_unknown_fields() || other->have_unknown_fields()) { + mutable_unknown_fields()->Swap(other->mutable_unknown_fields()); + } + } + + inline void* raw_arena_ptr() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + return ptr_; + } + + private: + void* ptr_; + + // Tagged pointer implementation. + enum { + // ptr_ is an Arena*. + kTagArena = 0, + // ptr_ is a Container*. + kTagContainer = 1, + }; + static const intptr_t kPtrTagMask = 1; + static const intptr_t kPtrValueMask = ~kPtrTagMask; + + // Accessors for pointer tag and pointer value. + inline int PtrTag() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + return reinterpret_cast(ptr_) & kPtrTagMask; + } + + template T* PtrValue() const { + return reinterpret_cast( + reinterpret_cast(ptr_) & kPtrValueMask); + } + + // If ptr_'s tag is kTagContainer, it points to an instance of this struct. + struct Container { + UnknownFieldSet unknown_fields_; + Arena* arena_; + }; + + UnknownFieldSet* mutable_unknown_fields_slow() GOOGLE_ATTRIBUTE_NOINLINE { + Arena* my_arena = arena(); + Container* container = Arena::Create(my_arena); + ptr_ = reinterpret_cast( + reinterpret_cast(container) | kTagContainer); + container->arena_ = my_arena; + return &(container->unknown_fields_); + } +}; + +// Temporary compatibility typedef. Remove once this is released in components +// and upb CL is submitted. +typedef InternalMetadataWithArena InternalMetadata; + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_METADATA_H__ diff --git a/src/google/protobuf/new_delete_capture.cc b/src/google/protobuf/new_delete_capture.cc new file mode 100644 index 00000000..baf42ffe --- /dev/null +++ b/src/google/protobuf/new_delete_capture.cc @@ -0,0 +1,121 @@ +// 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. + +// This file exists for testing allocation behavior when using arenas by hooking +// new/delete. It is a copy of //experimental/mvels/util/new_delete_capture.cc. + +#include + +#include + +#include +#include +#include + +namespace google { +namespace { + +pthread_t gthread; +protobuf_unittest::NewDeleteCapture *ghooked_instance = NULL; +SpinLock gspinlock(base::LINKER_INITIALIZED); + +} // namespace + +namespace protobuf_unittest { + +NewDeleteCapture::NewDeleteCapture() + : alloc_count_(0), + alloc_size_(0), + alloc_ptr_(NULL), + free_count_(0), + free_ptr_(NULL) {} + +NewDeleteCapture::~NewDeleteCapture() { Unhook(); } + +void NewDeleteCapture::Reset() { + alloc_count_ = 0; + alloc_size_ = 0; + free_count_ = 0; + alloc_ptr_ = NULL; + free_ptr_ = NULL; +} + +bool NewDeleteCapture::Hook(bool reset) { + SpinLockHolder spinlock(&gspinlock); + if (ghooked_instance != this) { + GOOGLE_CHECK(ghooked_instance == NULL) + << " NewDeleteCapture can have only 1 active instance"; + GOOGLE_CHECK(MallocHook::AddNewHook(NewHook)); + GOOGLE_CHECK(MallocHook::AddDeleteHook(DeleteHook)); + gthread = pthread_self(); + ghooked_instance = this; + if (reset) { + Reset(); + } + return true; + } + return false; +} + +bool NewDeleteCapture::Unhook() { + SpinLockHolder spinlock(&gspinlock); + if (ghooked_instance == this) { + gthread = pthread_t(); + ghooked_instance = NULL; + GOOGLE_CHECK(MallocHook::RemoveDeleteHook(DeleteHook)); + GOOGLE_CHECK(MallocHook::RemoveNewHook(NewHook)); + return true; + } + return false; +} + +void NewDeleteCapture::NewHook(const void *ptr, size_t size) { + SpinLockHolder spinlock(&gspinlock); + if (gthread == pthread_self()) { + auto &rthis = *ghooked_instance; + if (++rthis.alloc_count_ == 1) { + rthis.alloc_size_ = size; + rthis.alloc_ptr_ = ptr; + } + } +} + +void NewDeleteCapture::DeleteHook(const void *ptr) { + SpinLockHolder spinlock(&gspinlock); + if (gthread == pthread_self()) { + auto &rthis = *ghooked_instance; + if (++rthis.free_count_ == 1) { + rthis.free_ptr_ = ptr; + } + } +} + +} // namespace protobuf_unittest +} // namespace google diff --git a/src/google/protobuf/new_delete_capture.h b/src/google/protobuf/new_delete_capture.h new file mode 100644 index 00000000..4ab550cd --- /dev/null +++ b/src/google/protobuf/new_delete_capture.h @@ -0,0 +1,175 @@ +// 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. + +// This file exists for testing allocation behavior when using arenas by hooking +// new/delete. It is a copy of //experimental/mvels/util/new_delete_capture.h. +// +// Copyright 2014 Google Inc. +// +// Author: Martijn Vels +// +// A simple class that captures memory allocations and deletes. +// +// This class is private to //strings and only intended to be used inside +// unit tests. It uses the MallocHook functionality to capture memory +// allocation and delete operations performed by the thread that activated +// a hook on a specific instance. +// +// The class captures the following information: +// - Total allocation count (new, malloc(), etc). +// - Total delete count (delete, free(), etc). +// - The size and returned pointer for the first memory allocation. +// - The pointer for the first delete operation. +// +// The latter 2 infos (size and pointer of first new/delete) are usefull in +// cases where you can closely scope a Hook() / Unhook sequence around a +// specific piece of code where you expect no more than 1 pair of new / delete +// operations. +// +// Sample usage where we expect a single unique alloc / free: +// +// NewDeleteCapture capture_alloc; +// const void *ptr; +// { +// capture_alloc.Hook(); +// MyAllocationClass my_instance(size); +// capture_alloc.Unhook(); +// +// ptr = my_instance.ptr(); +// GOOGLE_CHECK_EQ(1, capture_alloc.alloc_count()); +// GOOGLE_CHECK_EQ(0, capture_alloc.free_count()); +// GOOGLE_CHECK_EQ(size, capture_alloc.alloc_size()); +// GOOGLE_CHECK_EQ(ptr, capture_alloc.alloc_ptr()); +// +// capture_alloc.Hook(); +// } +// capture_alloc.Unhook(); +// GOOGLE_CHECK_EQ(1, capture_alloc.alloc_count()); +// GOOGLE_CHECK_EQ(1, capture_alloc.free_count()); +// GOOGLE_CHECK_EQ(ptr, capture_alloc.free_ptr()); +// +// You can only have one NewDeleteCapture instance active at the time. It is +// total valid to have many instances in different threads, but only one +// instance can have a hook active. +// +// Legal: +// +// NewDeleteCapture capture_alloc1; +// NewDeleteCapture capture_alloc2; +// const void *ptr; +// { +// capture_alloc1.Hook(); +// MyAllocationClass my_instance(size); +// capture_alloc1.Unhook(); +// +// capture_alloc2.Hook(); +// my_instance.reset(size); +// capture_alloc2.Unhook(); +// } +// +// Illegal: +// +// NewDeleteCapture capture_alloc1; +// NewDeleteCapture capture_alloc2; +// const void *ptr; +// { +// capture_alloc1.Hook(); +// MyAllocationClass my_instance(size); +// +// capture_alloc2.Hook(); +// my_instance.reset(size); +// +// capture_alloc1.Unhook(); +// capture_alloc2.Unhook(); +// } +// +#ifndef GOOGLE_PROTOBUF_NEW_DELETE_CAPTURE_H__ +#define GOOGLE_PROTOBUF_NEW_DELETE_CAPTURE_H__ + +#include + +namespace google { +namespace protobuf_unittest { + +class NewDeleteCapture { + public: + // Creates a new inactive capture instance + NewDeleteCapture(); + + // Destroys this capture instance. Active hooks are automatically removed. + ~NewDeleteCapture(); + + // Activates a hook on this instance. If reset is true (the default), all + // internal counters will be reset to 0. + // Returns true if the hook was activated, false if this instance already + // owned the hook. + // Requires no other instance owning the hook (check fails) + bool Hook(bool reset = true); + + // De-activate the hook on this instance. + // Returns true if the hook was removed, false if this instance did not own + // the hook. + bool Unhook(); + + // Resets all counters to 0 + void Reset(); + + // Returns the total number of allocations (new, malloc(), etc) + size_t alloc_count() const { return alloc_count_; } + + // Returns the total number of deletes (delete, free(), etc) + size_t free_count() const { return free_count_; } + + // Returns the size of the first observed allocation + size_t alloc_size() const { return alloc_size_; } + + // Returns the allocated ptr of the first observed allocation + const void *alloc_ptr() const { return alloc_ptr_; } + + // Returns the ptr of the first observed delete + const void* free_ptr() const { return free_ptr_; } + + private: + static void NewHook(const void *ptr, size_t size); + static void DeleteHook(const void *ptr); + + private: + size_t alloc_count_; + size_t alloc_size_; + const void *alloc_ptr_; + + size_t free_count_; + const void *free_ptr_; +}; + +} // namespace protobuf_unittest + +} // namespace google +#endif // GOOGLE_PROTOBUF_NEW_DELETE_CAPTURE_H__ diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc new file mode 100644 index 00000000..f248327c --- /dev/null +++ b/src/google/protobuf/no_field_presence_test.cc @@ -0,0 +1,526 @@ +// 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 + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace { + +// Helper: checks that all fields have default (zero/empty) values. +void CheckDefaultValues( + const proto2_nofieldpresence_unittest::TestAllTypes& m) { + EXPECT_EQ(0, m.optional_int32()); + EXPECT_EQ(0, m.optional_int64()); + EXPECT_EQ(0, m.optional_uint32()); + EXPECT_EQ(0, m.optional_uint64()); + EXPECT_EQ(0, m.optional_sint32()); + EXPECT_EQ(0, m.optional_sint64()); + EXPECT_EQ(0, m.optional_fixed32()); + EXPECT_EQ(0, m.optional_fixed64()); + EXPECT_EQ(0, m.optional_sfixed32()); + EXPECT_EQ(0, m.optional_sfixed64()); + EXPECT_EQ(0, m.optional_float()); + EXPECT_EQ(0, m.optional_double()); + EXPECT_EQ(false, m.optional_bool()); + EXPECT_EQ(0, m.optional_string().size()); + EXPECT_EQ(0, m.optional_bytes().size()); + + EXPECT_EQ(false, m.has_optional_nested_message()); + // accessor for message fields returns default instance when not present + EXPECT_EQ(0, m.optional_nested_message().bb()); + EXPECT_EQ(false, m.has_optional_proto2_message()); + // Embedded proto2 messages still have proto2 semantics, e.g. non-zero default + // values. Here the submessage is not present but its accessor returns the + // default instance. + EXPECT_EQ(41, m.optional_proto2_message().default_int32()); + EXPECT_EQ(false, m.has_optional_foreign_message()); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_FOO, + m.optional_nested_enum()); + EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_FOO, + m.optional_foreign_enum()); + + + EXPECT_EQ(0, m.repeated_int32_size()); + EXPECT_EQ(0, m.repeated_int64_size()); + EXPECT_EQ(0, m.repeated_uint32_size()); + EXPECT_EQ(0, m.repeated_uint64_size()); + EXPECT_EQ(0, m.repeated_sint32_size()); + EXPECT_EQ(0, m.repeated_sint64_size()); + EXPECT_EQ(0, m.repeated_fixed32_size()); + EXPECT_EQ(0, m.repeated_fixed64_size()); + EXPECT_EQ(0, m.repeated_sfixed32_size()); + EXPECT_EQ(0, m.repeated_sfixed64_size()); + EXPECT_EQ(0, m.repeated_float_size()); + EXPECT_EQ(0, m.repeated_double_size()); + EXPECT_EQ(0, m.repeated_bool_size()); + EXPECT_EQ(0, m.repeated_string_size()); + EXPECT_EQ(0, m.repeated_bytes_size()); + EXPECT_EQ(0, m.repeated_nested_message_size()); + EXPECT_EQ(0, m.repeated_foreign_message_size()); + EXPECT_EQ(0, m.repeated_proto2_message_size()); + EXPECT_EQ(0, m.repeated_nested_enum_size()); + EXPECT_EQ(0, m.repeated_foreign_enum_size()); + EXPECT_EQ(0, m.repeated_lazy_message_size()); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::ONEOF_FIELD_NOT_SET, + m.oneof_field_case()); +} + +void FillValues(proto2_nofieldpresence_unittest::TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_int64(101); + m->set_optional_uint32(102); + m->set_optional_uint64(103); + m->set_optional_sint32(104); + m->set_optional_sint64(105); + m->set_optional_fixed32(106); + m->set_optional_fixed64(107); + m->set_optional_sfixed32(108); + m->set_optional_sfixed64(109); + m->set_optional_float(110.0); + m->set_optional_double(111.0); + m->set_optional_bool(true); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->mutable_optional_proto2_message()->set_optional_int32(44); + m->set_optional_nested_enum( + proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto2_nofieldpresence_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_int64(101); + m->add_repeated_uint32(102); + m->add_repeated_uint64(103); + m->add_repeated_sint32(104); + m->add_repeated_sint64(105); + m->add_repeated_fixed32(106); + m->add_repeated_fixed64(107); + m->add_repeated_sfixed32(108); + m->add_repeated_sfixed64(109); + m->add_repeated_float(110.0); + m->add_repeated_double(111.0); + m->add_repeated_bool(true); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_proto2_message()->set_optional_int32(48); + m->add_repeated_nested_enum( + proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto2_nofieldpresence_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void CheckNonDefaultValues( +const proto2_nofieldpresence_unittest::TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ(101, m.optional_int64()); + EXPECT_EQ(102, m.optional_uint32()); + EXPECT_EQ(103, m.optional_uint64()); + EXPECT_EQ(104, m.optional_sint32()); + EXPECT_EQ(105, m.optional_sint64()); + EXPECT_EQ(106, m.optional_fixed32()); + EXPECT_EQ(107, m.optional_fixed64()); + EXPECT_EQ(108, m.optional_sfixed32()); + EXPECT_EQ(109, m.optional_sfixed64()); + EXPECT_EQ(110.0, m.optional_float()); + EXPECT_EQ(111.0, m.optional_double()); + EXPECT_EQ(true, m.optional_bool()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(true, m.has_optional_proto2_message()); + EXPECT_EQ(44, m.optional_proto2_message().optional_int32()); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_int64_size()); + EXPECT_EQ(101, m.repeated_int64(0)); + EXPECT_EQ(1, m.repeated_uint32_size()); + EXPECT_EQ(102, m.repeated_uint32(0)); + EXPECT_EQ(1, m.repeated_uint64_size()); + EXPECT_EQ(103, m.repeated_uint64(0)); + EXPECT_EQ(1, m.repeated_sint32_size()); + EXPECT_EQ(104, m.repeated_sint32(0)); + EXPECT_EQ(1, m.repeated_sint64_size()); + EXPECT_EQ(105, m.repeated_sint64(0)); + EXPECT_EQ(1, m.repeated_fixed32_size()); + EXPECT_EQ(106, m.repeated_fixed32(0)); + EXPECT_EQ(1, m.repeated_fixed64_size()); + EXPECT_EQ(107, m.repeated_fixed64(0)); + EXPECT_EQ(1, m.repeated_sfixed32_size()); + EXPECT_EQ(108, m.repeated_sfixed32(0)); + EXPECT_EQ(1, m.repeated_sfixed64_size()); + EXPECT_EQ(109, m.repeated_sfixed64(0)); + EXPECT_EQ(1, m.repeated_float_size()); + EXPECT_EQ(110.0, m.repeated_float(0)); + EXPECT_EQ(1, m.repeated_double_size()); + EXPECT_EQ(111.0, m.repeated_double(0)); + EXPECT_EQ(1, m.repeated_bool_size()); + EXPECT_EQ(true, m.repeated_bool(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_proto2_message_size()); + EXPECT_EQ(48, m.repeated_proto2_message(0).optional_int32()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +TEST(NoFieldPresenceTest, BasicMessageTest) { + proto2_nofieldpresence_unittest::TestAllTypes message; + // Check default values, fill all fields, check values. We just want to + // exercise the basic getters/setter paths here to make sure no + // field-presence-related changes broke these. + CheckDefaultValues(message); + FillValues(&message); + CheckNonDefaultValues(message); + + // Clear() should be equivalent to getting a freshly-constructed message. + message.Clear(); + CheckDefaultValues(message); +} + +TEST(NoFieldPresenceTest, MessageFieldPresenceTest) { + // check that presence still works properly for message fields. + proto2_nofieldpresence_unittest::TestAllTypes message; + EXPECT_EQ(false, message.has_optional_nested_message()); + // Getter should fetch default instance, and not cause the field to become + // present. + EXPECT_EQ(0, message.optional_nested_message().bb()); + EXPECT_EQ(false, message.has_optional_nested_message()); + message.mutable_optional_nested_message()->set_bb(42); + EXPECT_EQ(true, message.has_optional_nested_message()); + message.clear_optional_nested_message(); + EXPECT_EQ(false, message.has_optional_nested_message()); + + // Likewise for a lazy message field. + EXPECT_EQ(false, message.has_optional_lazy_message()); + // Getter should fetch default instance, and not cause the field to become + // present. + EXPECT_EQ(0, message.optional_lazy_message().bb()); + EXPECT_EQ(false, message.has_optional_lazy_message()); + message.mutable_optional_lazy_message()->set_bb(42); + EXPECT_EQ(true, message.has_optional_lazy_message()); + message.clear_optional_lazy_message(); + EXPECT_EQ(false, message.has_optional_lazy_message()); +} + +TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { + // check that HasField reports true on all scalar fields. Check that it + // behaves properly for message fields. + + proto2_nofieldpresence_unittest::TestAllTypes message; + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* desc = message.GetDescriptor(); + + // Check initial state: scalars not present (due to need to be consistent with + // MergeFrom()), message fields not present, oneofs not present. + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* field = desc->field(i); + if (field->is_repeated()) continue; + EXPECT_EQ(false, r->HasField(message, field)); + } + + // Fill all fields, expect everything to report true (check oneofs below). + FillValues(&message); + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* field = desc->field(i); + if (field->is_repeated() || field->containing_oneof()) { + continue; + } + if (field->options().ctype() != google::protobuf::FieldOptions::STRING) { + continue; + } + EXPECT_EQ(true, r->HasField(message, field)); + } + + message.Clear(); + + // Check zero/empty-means-not-present semantics. + const google::protobuf::FieldDescriptor* field_int32 = desc->FindFieldByName( + "optional_int32"); + const google::protobuf::FieldDescriptor* field_double = desc->FindFieldByName( + "optional_double"); + const google::protobuf::FieldDescriptor* field_string = desc->FindFieldByName( + "optional_string"); + + EXPECT_EQ(false, r->HasField(message, field_int32)); + EXPECT_EQ(false, r->HasField(message, field_double)); + EXPECT_EQ(false, r->HasField(message, field_string)); + + message.set_optional_int32(42); + EXPECT_EQ(true, r->HasField(message, field_int32)); + message.set_optional_int32(0); + EXPECT_EQ(false, r->HasField(message, field_int32)); + + message.set_optional_double(42.0); + EXPECT_EQ(true, r->HasField(message, field_double)); + message.set_optional_double(0.0); + EXPECT_EQ(false, r->HasField(message, field_double)); + + message.set_optional_string("test"); + EXPECT_EQ(true, r->HasField(message, field_string)); + message.set_optional_string(""); + EXPECT_EQ(false, r->HasField(message, field_string)); +} + +TEST(NoFieldPresenceTest, HasFieldOneofsTest) { + // check that HasField behaves properly for oneofs. + proto2_nofieldpresence_unittest::TestAllTypes message; + + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* desc = message.GetDescriptor(); + const google::protobuf::FieldDescriptor* desc_oneof_uint32 = + desc->FindFieldByName("oneof_uint32"); + const google::protobuf::FieldDescriptor* desc_oneof_nested_message = + desc->FindFieldByName("oneof_nested_message"); + const google::protobuf::FieldDescriptor* desc_oneof_string = + desc->FindFieldByName("oneof_string"); + GOOGLE_CHECK_NOTNULL(desc_oneof_uint32); + GOOGLE_CHECK_NOTNULL(desc_oneof_nested_message); + GOOGLE_CHECK_NOTNULL(desc_oneof_string); + + EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_string)); + + message.set_oneof_string("test"); + EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message)); + EXPECT_EQ(true, r->HasField(message, desc_oneof_string)); + message.mutable_oneof_nested_message()->set_bb(42); + EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32)); + EXPECT_EQ(true, r->HasField(message, desc_oneof_nested_message)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_string)); + + message.Clear(); + EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message)); + EXPECT_EQ(false, r->HasField(message, desc_oneof_string)); +} + +TEST(NoFieldPresenceTest, DontSerializeDefaultValuesTest) { + // check that serialized data contains only non-zero numeric fields/non-empty + // string/byte fields. + proto2_nofieldpresence_unittest::TestAllTypes message; + string output; + + // All default values -> no output. + message.SerializeToString(&output); + EXPECT_EQ(0, output.size()); + + // Zero values -> still no output. + message.set_optional_int32(0); + message.set_optional_int64(0); + message.set_optional_uint32(0); + message.set_optional_uint64(0); + message.set_optional_sint32(0); + message.set_optional_sint64(0); + message.set_optional_fixed32(0); + message.set_optional_fixed64(0); + message.set_optional_sfixed32(0); + message.set_optional_sfixed64(0); + message.set_optional_float(0); + message.set_optional_double(0); + message.set_optional_bool(0); + message.set_optional_string(""); + message.set_optional_bytes(""); + message.set_optional_nested_enum( + proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_FOO); // first enum entry + message.set_optional_foreign_enum( + proto2_nofieldpresence_unittest::FOREIGN_FOO); // first enum entry + + message.SerializeToString(&output); + EXPECT_EQ(0, output.size()); + + message.set_optional_int32(1); + message.SerializeToString(&output); + EXPECT_EQ(2, output.size()); + EXPECT_EQ("\x08\x01", output); + + message.set_optional_int32(0); + message.SerializeToString(&output); + EXPECT_EQ(0, output.size()); +} + +TEST(NoFieldPresenceTest, MergeFromIfNonzeroTest) { + // check that MergeFrom copies if nonzero/nondefault only. + proto2_nofieldpresence_unittest::TestAllTypes source; + proto2_nofieldpresence_unittest::TestAllTypes dest; + + dest.set_optional_int32(42); + dest.set_optional_string("test"); + source.set_optional_int32(0); + source.set_optional_string(""); + // MergeFrom() copies only if present in serialization, i.e., non-zero. + dest.MergeFrom(source); + EXPECT_EQ(42, dest.optional_int32()); + EXPECT_EQ("test", dest.optional_string()); + + source.set_optional_int32(84); + source.set_optional_string("test2"); + dest.MergeFrom(source); + EXPECT_EQ(84, dest.optional_int32()); + EXPECT_EQ("test2", dest.optional_string()); +} + +TEST(NoFieldPresenceTest, IsInitializedTest) { + // Check that IsInitialized works properly. + proto2_nofieldpresence_unittest::TestProto2Required message; + + EXPECT_EQ(true, message.IsInitialized()); + message.mutable_proto2()->set_a(1); + EXPECT_EQ(false, message.IsInitialized()); + message.mutable_proto2()->set_b(1); + EXPECT_EQ(false, message.IsInitialized()); + message.mutable_proto2()->set_c(1); + EXPECT_EQ(true, message.IsInitialized()); +} + +TEST(NoFieldPresenceTest, LazyMessageFieldHasBit) { + // Check that has-bit interaction with lazy message works (has-bit before and + // after lazy decode). + proto2_nofieldpresence_unittest::TestAllTypes message; + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* desc = message.GetDescriptor(); + const google::protobuf::FieldDescriptor* field = desc->FindFieldByName( + "optional_lazy_message"); + GOOGLE_CHECK_NOTNULL(field); + + EXPECT_EQ(false, message.has_optional_lazy_message()); + EXPECT_EQ(false, r->HasField(message, field)); + + message.mutable_optional_lazy_message()->set_bb(42); + EXPECT_EQ(true, message.has_optional_lazy_message()); + EXPECT_EQ(true, r->HasField(message, field)); + + // Serialize and parse with a new message object so that lazy field on new + // object is in unparsed state. + string output; + message.SerializeToString(&output); + proto2_nofieldpresence_unittest::TestAllTypes message2; + message2.ParseFromString(output); + + EXPECT_EQ(true, message2.has_optional_lazy_message()); + EXPECT_EQ(true, r->HasField(message2, field)); + + // Access field to force lazy parse. + EXPECT_EQ(42, message.optional_lazy_message().bb()); + EXPECT_EQ(true, message2.has_optional_lazy_message()); + EXPECT_EQ(true, r->HasField(message2, field)); +} + +TEST(NoFieldPresenceTest, OneofPresence) { + proto2_nofieldpresence_unittest::TestAllTypes message; + // oneof fields still have field presence -- ensure that this goes on the wire + // even though its value is the empty string. + message.set_oneof_string(""); + string serialized; + message.SerializeToString(&serialized); + // Tag: 113 --> tag is (113 << 3) | 2 (length delimited) = 906 + // varint: 0x8a 0x07 + // Length: 0x00 + EXPECT_EQ(3, serialized.size()); + EXPECT_EQ(static_cast(0x8a), serialized.at(0)); + EXPECT_EQ(static_cast(0x07), serialized.at(1)); + EXPECT_EQ(static_cast(0x00), serialized.at(2)); + + message.Clear(); + EXPECT_TRUE(message.ParseFromString(serialized)); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString, + message.oneof_field_case()); + + // Also test int32 and enum fields. + message.Clear(); + message.set_oneof_uint32(0); // would not go on wire if ordinary field. + message.SerializeToString(&serialized); + EXPECT_EQ(3, serialized.size()); + EXPECT_TRUE(message.ParseFromString(serialized)); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofUint32, + message.oneof_field_case()); + + message.Clear(); + message.set_oneof_enum(proto2_nofieldpresence_unittest:: + TestAllTypes_NestedEnum_FOO); // default value. + message.SerializeToString(&serialized); + EXPECT_EQ(3, serialized.size()); + EXPECT_TRUE(message.ParseFromString(serialized)); + EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofEnum, + message.oneof_field_case()); + + message.Clear(); + message.set_oneof_string("test"); + message.clear_oneof_string(); + EXPECT_EQ(0, message.ByteSize()); +} + +} // namespace +} // namespace protobuf + +} // namespace google diff --git a/src/google/protobuf/preserve_unknown_enum_test.cc b/src/google/protobuf/preserve_unknown_enum_test.cc new file mode 100644 index 00000000..e988a5cb --- /dev/null +++ b/src/google/protobuf/preserve_unknown_enum_test.cc @@ -0,0 +1,230 @@ +// 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 +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace { + +void FillMessage( + proto2_preserve_unknown_enum_unittest::MyMessagePlusExtra* message) { + message->set_e( + proto2_preserve_unknown_enum_unittest::E_EXTRA); + message->add_repeated_e( + proto2_preserve_unknown_enum_unittest::E_EXTRA); + message->add_repeated_packed_e( + proto2_preserve_unknown_enum_unittest::E_EXTRA); + message->set_oneof_e_1( + proto2_preserve_unknown_enum_unittest::E_EXTRA); +} + +void CheckMessage( + const proto2_preserve_unknown_enum_unittest::MyMessagePlusExtra& message) { + EXPECT_EQ(proto2_preserve_unknown_enum_unittest::E_EXTRA, + message.e()); + EXPECT_EQ(1, message.repeated_e_size()); + EXPECT_EQ(proto2_preserve_unknown_enum_unittest::E_EXTRA, + message.repeated_e(0)); + EXPECT_EQ(1, message.repeated_packed_e_size()); + EXPECT_EQ(proto2_preserve_unknown_enum_unittest::E_EXTRA, + message.repeated_packed_e(0)); + EXPECT_EQ(proto2_preserve_unknown_enum_unittest::E_EXTRA, + message.oneof_e_1()); +} + +void CheckMessage( + const proto2_preserve_unknown_enum_unittest::MyMessage& message) { + EXPECT_EQ(static_cast( + proto2_preserve_unknown_enum_unittest::E_EXTRA), + static_cast(message.e())); + EXPECT_EQ(1, message.repeated_e_size()); + EXPECT_EQ(static_cast( + proto2_preserve_unknown_enum_unittest::E_EXTRA), + static_cast(message.repeated_e(0))); + EXPECT_EQ(1, message.repeated_packed_e_size()); + EXPECT_EQ(static_cast( + proto2_preserve_unknown_enum_unittest::E_EXTRA), + static_cast(message.repeated_packed_e(0))); + EXPECT_EQ(static_cast( + proto2_preserve_unknown_enum_unittest::E_EXTRA), + static_cast(message.oneof_e_1())); +} + +} // anonymous namespace + +// Test that parsing preserves an unknown value in the enum field and does not +// punt it to the UnknownFieldSet. +TEST(PreserveUnknownEnumTest, PreserveParseAndSerialize) { + proto2_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message; + FillMessage(&orig_message); + string serialized; + orig_message.SerializeToString(&serialized); + + proto2_preserve_unknown_enum_unittest::MyMessage message; + EXPECT_EQ(true, message.ParseFromString(serialized)); + CheckMessage(message); + + serialized.clear(); + message.SerializeToString(&serialized); + EXPECT_EQ(true, orig_message.ParseFromString(serialized)); + CheckMessage(orig_message); +} + +// Test that reflection based implementation also keeps unknown enum values and +// doesn't put them into UnknownFieldSet. +TEST(PreserveUnknownEnumTest, PreserveParseAndSerializeDynamicMessage) { + proto2_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message; + FillMessage(&orig_message); + string serialized = orig_message.SerializeAsString(); + + google::protobuf::DynamicMessageFactory factory; + scoped_ptr message(factory.GetPrototype( + proto2_preserve_unknown_enum_unittest::MyMessage::descriptor())->New()); + EXPECT_EQ(true, message->ParseFromString(serialized)); + message->DiscardUnknownFields(); + + serialized = message->SerializeAsString(); + EXPECT_EQ(true, orig_message.ParseFromString(serialized)); + CheckMessage(orig_message); +} + +// Test that reflection provides EnumValueDescriptors for unknown values. +TEST(PreserveUnknownEnumTest, DynamicEnumValueDescriptors) { + proto2_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message; + FillMessage(&orig_message); + string serialized; + orig_message.SerializeToString(&serialized); + + proto2_preserve_unknown_enum_unittest::MyMessage message; + EXPECT_EQ(true, message.ParseFromString(serialized)); + CheckMessage(message); + + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* d = message.GetDescriptor(); + const google::protobuf::FieldDescriptor* field = d->FindFieldByName("e"); + + // This should dynamically create an EnumValueDescriptor. + const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message, field); + EXPECT_EQ(enum_value->number(), + static_cast(proto2_preserve_unknown_enum_unittest::E_EXTRA)); + + // Fetching value for a second time should return the same pointer. + const google::protobuf::EnumValueDescriptor* enum_value_second = + r->GetEnum(message, field); + EXPECT_EQ(enum_value, enum_value_second); + + // Check the repeated case too. + const google::protobuf::FieldDescriptor* repeated_field = + d->FindFieldByName("repeated_e"); + enum_value = r->GetRepeatedEnum(message, repeated_field, 0); + EXPECT_EQ(enum_value->number(), + static_cast(proto2_preserve_unknown_enum_unittest::E_EXTRA)); + // Should reuse the same EnumValueDescriptor, even for a different field. + EXPECT_EQ(enum_value, enum_value_second); + + // We should be able to use the returned value descriptor to set a value on + // another message. + google::protobuf::Message* m = message.New(); + r->SetEnum(m, field, enum_value); + EXPECT_EQ(enum_value, r->GetEnum(*m, field)); + delete m; +} + +// Test that the new integer-based enum reflection API works. +TEST(PreserveUnknownEnumTest, IntegerEnumReflectionAPI) { + proto2_preserve_unknown_enum_unittest::MyMessage message; + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* d = message.GetDescriptor(); + + const google::protobuf::FieldDescriptor* singular_field = d->FindFieldByName("e"); + const google::protobuf::FieldDescriptor* repeated_field = + d->FindFieldByName("repeated_e"); + + r->SetEnumValue(&message, singular_field, 42); + EXPECT_EQ(42, r->GetEnumValue(message, singular_field)); + r->AddEnumValue(&message, repeated_field, 42); + r->AddEnumValue(&message, repeated_field, 42); + EXPECT_EQ(42, r->GetRepeatedEnumValue(message, repeated_field, 0)); + r->SetRepeatedEnumValue(&message, repeated_field, 1, 84); + EXPECT_EQ(84, r->GetRepeatedEnumValue(message, repeated_field, 1)); + const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message, + singular_field); + EXPECT_EQ(42, enum_value->number()); +} + +// Test that the EnumValue API works properly for proto2 messages as well. +TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) { + protobuf_unittest::TestAllTypes message; // proto2 message + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* d = message.GetDescriptor(); + const google::protobuf::FieldDescriptor* singular_field = + d->FindFieldByName("optional_nested_enum"); + const google::protobuf::FieldDescriptor* repeated_field = + d->FindFieldByName("repeated_nested_enum"); + // Add one element to the repeated field so that we can test + // SetRepeatedEnumValue. + const google::protobuf::EnumValueDescriptor* enum_value = + repeated_field->enum_type()->FindValueByName("BAR"); + EXPECT_TRUE(enum_value != NULL); + r->AddEnum(&message, repeated_field, enum_value); + + // Enum-field integer-based setters GOOGLE_DCHECK-fail on invalid values, in order to + // remain consistent with proto2 generated code. + EXPECT_DEBUG_DEATH({ + r->SetEnumValue(&message, singular_field, 4242); + r->GetEnum(message, singular_field)->number(); + }, "SetEnumValue accepts only valid integer values"); + EXPECT_DEBUG_DEATH({ + r->SetRepeatedEnumValue(&message, repeated_field, 0, 4242); + r->GetRepeatedEnum(message, repeated_field, 0); + }, "SetRepeatedEnumValue accepts only valid integer values"); + EXPECT_DEBUG_DEATH({ + r->AddEnumValue(&message, repeated_field, 4242); + r->GetRepeatedEnum(message, repeated_field, 1); + }, "AddEnumValue accepts only valid integer values"); +} + +TEST(PreserveUnknownEnumTest, SupportsUnknownEnumValuesAPI) { + protobuf_unittest::TestAllTypes proto2_message; + proto2_preserve_unknown_enum_unittest::MyMessage new_message; + + const google::protobuf::Reflection* proto2_reflection = proto2_message.GetReflection(); + const google::protobuf::Reflection* new_reflection = new_message.GetReflection(); + + EXPECT_FALSE(proto2_reflection->SupportsUnknownEnumValues()); + EXPECT_TRUE(new_reflection->SupportsUnknownEnumValues()); +} +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc new file mode 100644 index 00000000..123e21ab --- /dev/null +++ b/src/google/protobuf/proto3_arena_unittest.cc @@ -0,0 +1,185 @@ +// 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 +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +using proto3_arena_unittest::TestAllTypes; + +namespace protobuf { +namespace { +// We selectively set/check a few representative fields rather than all fields +// as this test is only expected to cover the basics of arena support. +void SetAllFields(TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->set_optional_nested_enum( + proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto3_arena_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_nested_enum( + proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto3_arena_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void ExpectAllFieldsSet(const TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto3_arena_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +// In this file we only test some basic functionalities of arena support in +// proto3 and expect the arena support to be fully tested in proto2 unittests +// because proto3 shares most code with proto2. + +TEST(ArenaTest, Parsing) { + TestAllTypes original; + SetAllFields(&original); + + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(*arena_message); +} + +TEST(ArenaTest, UnknownFields) { + TestAllTypes original; + SetAllFields(&original); + + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(*arena_message); + + // In proto3 we can still get a pointer to the UnknownFieldSet through + // reflection API. + UnknownFieldSet* unknown_fields = + arena_message->GetReflection()->MutableUnknownFields(arena_message); + // We can modify this UnknownFieldSet. + unknown_fields->AddVarint(1, 2); + // But the change will never will serialized back. + ASSERT_EQ(original.ByteSize(), arena_message->ByteSize()); + ASSERT_TRUE( + arena_message->GetReflection()->GetUnknownFields(*arena_message).empty()); +} + +TEST(ArenaTest, Swap) { + Arena arena1; + Arena arena2; + + // Test Swap(). + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); +} + +TEST(ArenaTest, SetAllocatedMessage) { + Arena arena; + TestAllTypes *arena_message = Arena::CreateMessage(&arena); + TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; + nested->set_bb(118); + arena_message->set_allocated_optional_nested_message(nested); + EXPECT_EQ(118, arena_message->optional_nested_message().bb()); +} + +TEST(ArenaTest, ReleaseMessage) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(118); + scoped_ptr nested( + arena_message->release_optional_nested_message()); + EXPECT_EQ(118, nested->bb()); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/proto_cast.h b/src/google/protobuf/proto_cast.h new file mode 100644 index 00000000..e25c219f --- /dev/null +++ b/src/google/protobuf/proto_cast.h @@ -0,0 +1,58 @@ +// 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_UTIL_PROTO_CAST_H__ +#define GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__ + +#include + +#include + +// proto_cast<> is used to simulate over-the-wire conversion of one +// proto message into another. This is primarily useful for unit tests +// which validate the version-compatibility semantics of protobufs. +// Usage is similar to C++-style typecasts: +// +// OldMessage old_message = /*...*/; +// NewMessage new_message = proto_cast(old_message); +namespace google { +template +NewProto proto_cast(const OldProto& old_proto) { + string wire_format; + GOOGLE_CHECK(old_proto.SerializeToString(&wire_format)); + + NewProto new_proto; + GOOGLE_CHECK(new_proto.ParseFromString(wire_format)); + return new_proto; +} + +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__ diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/proto_cast_test.cc new file mode 100644 index 00000000..eb101eb6 --- /dev/null +++ b/src/google/protobuf/proto_cast_test.cc @@ -0,0 +1,60 @@ +// 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 + +#include +#include +#include + +namespace google { +using google::protobuf::util::UpRevision; +using google::protobuf::util::DownRevision; + +namespace { + +TEST(ProtoCastTest, V2KnownValue) { + UpRevision sender; + sender.set_value(UpRevision::NONDEFAULT_VALUE); + + DownRevision receiver = proto_cast(sender); + ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value()); +} + +TEST(ProtoCastTest, V2UnknownValue) { + UpRevision sender; + sender.set_value(UpRevision::NEW_VALUE); + + DownRevision receiver = proto_cast(sender); + ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value()); +} + +} // namespace +} // namespace google diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h new file mode 100644 index 00000000..17d89a18 --- /dev/null +++ b/src/google/protobuf/reflection.h @@ -0,0 +1,306 @@ +// 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. + +// This header defines the RepeatedFieldRef class template used to access +// repeated fields with protobuf reflection API. +#ifndef GOOGLE_PROTOBUF_REFLECTION_H__ +#define GOOGLE_PROTOBUF_REFLECTION_H__ + +#include + +namespace google { +namespace protobuf { +namespace internal { +template +struct RefTypeTraits; +} // namespace internal + +template +RepeatedFieldRef Reflection::GetRepeatedFieldRef( + const Message& message, const FieldDescriptor* field) const { + return RepeatedFieldRef(message, field); +} + +template +MutableRepeatedFieldRef Reflection::GetMutableRepeatedFieldRef( + Message* message, const FieldDescriptor* field) const { + return MutableRepeatedFieldRef(message, field); +} + +// RepeatedFieldRef definition for non-message types. +template +class RepeatedFieldRef< + T, typename internal::enable_if::value>::type> { + typedef typename internal::RefTypeTraits::iterator IteratorType; + typedef typename internal::RefTypeTraits::AccessorType AccessorType; + + public: + bool empty() const { + return accessor_->IsEmpty(data_); + } + int size() const { + return accessor_->Size(data_); + } + T Get(int index) const { + return accessor_->template Get(data_, index); + } + + typedef IteratorType iterator; + typedef IteratorType const_iterator; + iterator begin() const { + return iterator(data_, accessor_, true); + } + iterator end() const { + return iterator(data_, accessor_, false); + } + + private: + friend class Reflection; + RepeatedFieldRef( + const Message& message, + const FieldDescriptor* field) { + const Reflection* reflection = message.GetReflection(); + data_ = reflection->RepeatedFieldData( + const_cast(&message), field, + internal::RefTypeTraits::cpp_type, NULL); + accessor_ = reflection->RepeatedFieldAccessor(field); + } + + const void* data_; + const AccessorType* accessor_; +}; + +// MutableRepeatedFieldRef definition for non-message types. +template +class MutableRepeatedFieldRef< + T, typename internal::enable_if::value>::type> { + typedef typename internal::RefTypeTraits::AccessorType AccessorType; + + public: + bool empty() const { + return accessor_->IsEmpty(data_); + } + int size() const { + return accessor_->Size(data_); + } + T Get(int index) const { + return accessor_->template Get(data_, index); + } + + void Set(int index, const T& value) const { + accessor_->template Set(data_, index, value); + } + void Add(const T& value) const { + accessor_->template Add(data_, value); + } + void RemoveLast() const { + accessor_->RemoveLast(data_); + } + void SwapElements(int index1, int index2) const { + accessor_->SwapElements(data_, index1, index2); + } + void Clear() const { + accessor_->Clear(data_); + } + + void Swap(const MutableRepeatedFieldRef& other) const { + accessor_->Swap(data_, other.accessor_, other.data_); + } + + template + void MergeFrom(const Container& container) const { + typedef typename Container::const_iterator Iterator; + for (Iterator it = container.begin(); it != container.end(); ++it) { + Add(*it); + } + } + template + void CopyFrom(const Container& container) const { + Clear(); + MergeFrom(container); + } + + private: + friend class Reflection; + MutableRepeatedFieldRef( + Message* message, + const FieldDescriptor* field) { + const Reflection* reflection = message->GetReflection(); + data_ = reflection->RepeatedFieldData( + message, field, internal::RefTypeTraits::cpp_type, NULL); + accessor_ = reflection->RepeatedFieldAccessor(field); + } + + void* data_; + const AccessorType* accessor_; +}; + +// RepeatedFieldRef definition for message types. +template +class RepeatedFieldRef< + T, typename internal::enable_if::value>::type> { + typedef typename internal::RefTypeTraits::iterator IteratorType; + typedef typename internal::RefTypeTraits::AccessorType AccessorType; + + public: + bool empty() const { + return accessor_->IsEmpty(data_); + } + int size() const { + return accessor_->Size(data_); + } + // This method returns a reference to the underlying message object if it + // exists. If a message object doesn't exist (e.g., data stored in serialized + // form), scratch_space will be filled with the data and a reference to it + // will be returned. + // + // Example: + // RepeatedFieldRef h = ... + // unique_ptr scratch_space(h.NewMessage()); + // const Message& item = h.Get(index, scratch_space.get()); + const T& Get(int index, T* scratch_space) const { + return *static_cast(accessor_->Get(data_, index, scratch_space)); + } + // Create a new message of the same type as the messages stored in this + // repeated field. Caller takes ownership of the returned object. + T* NewMessage() const { + return static_cast(default_instance_->New()); + } + + typedef IteratorType iterator; + typedef IteratorType const_iterator; + iterator begin() const { + return iterator(data_, accessor_, true, NewMessage()); + } + iterator end() const { + return iterator(data_, accessor_, false, NewMessage()); + } + + private: + friend class Reflection; + RepeatedFieldRef( + const Message& message, + const FieldDescriptor* field) { + const Reflection* reflection = message.GetReflection(); + data_ = reflection->RepeatedFieldData( + const_cast(&message), field, + internal::RefTypeTraits::cpp_type, + internal::RefTypeTraits::GetMessageFieldDescriptor()); + accessor_ = reflection->RepeatedFieldAccessor(field); + default_instance_ = + reflection->GetMessageFactory()->GetPrototype(field->message_type()); + } + + const void* data_; + const AccessorType* accessor_; + const Message* default_instance_; +}; + +// MutableRepeatedFieldRef definition for non-message types. +template +class MutableRepeatedFieldRef< + T, typename internal::enable_if::value>::type> { + typedef typename internal::RefTypeTraits::AccessorType AccessorType; + + public: + bool empty() const { + return accessor_->IsEmpty(data_); + } + int size() const { + return accessor_->Size(data_); + } + // See comments for RepeatedFieldRef::Get() + const T& Get(int index, T* scratch_space) const { + return *static_cast(accessor_->Get(data_, index, scratch_space)); + } + // Create a new message of the same type as the messages stored in this + // repeated field. Caller takes ownership of the returned object. + T* NewMessage() const { + return static_cast(default_instance_->New()); + } + + void Set(int index, const T& value) const { + accessor_->Set(data_, index, &value); + } + void Add(const T& value) const { + accessor_->Add(data_, &value); + } + void RemoveLast() const { + accessor_->RemoveLast(data_); + } + void SwapElements(int index1, int index2) const { + accessor_->SwapElements(data_, index1, index2); + } + void Clear() const { + accessor_->Clear(data_); + } + + void Swap(const MutableRepeatedFieldRef& other) const { + accessor_->Swap(data_, other.accessor_, other.data_); + } + + template + void MergeFrom(const Container& container) const { + typedef typename Container::const_iterator Iterator; + for (Iterator it = container.begin(); it != container.end(); ++it) { + Add(*it); + } + } + template + void CopyFrom(const Container& container) const { + Clear(); + MergeFrom(container); + } + + private: + friend class Reflection; + MutableRepeatedFieldRef( + Message* message, + const FieldDescriptor* field) { + const Reflection* reflection = message->GetReflection(); + data_ = reflection->RepeatedFieldData( + message, field, internal::RefTypeTraits::cpp_type, + internal::RefTypeTraits::GetMessageFieldDescriptor()); + accessor_ = reflection->RepeatedFieldAccessor(field); + default_instance_ = + reflection->GetMessageFactory()->GetPrototype(field->message_type()); + } + + void* data_; + const AccessorType* accessor_; + const Message* default_instance_; +}; +} // namespace protobuf +} // namespace google + +// Implementation details for (Mutable)RepeatedFieldRef. +#include + +#endif // GOOGLE_PROTOBUF_REFLECTION_H__ diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h new file mode 100644 index 00000000..e25e193c --- /dev/null +++ b/src/google/protobuf/reflection_internal.h @@ -0,0 +1,310 @@ +// 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_REFLECTION_INTERNAL_H__ +#define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace internal { +// A base class for RepeatedFieldAccessor implementations that can support +// random-access efficiently. All iterator methods delegates the work to +// corresponding random-access methods. +class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor { + public: + virtual ~RandomAccessRepeatedFieldAccessor() {} + + virtual Iterator* BeginIterator(const Field* data) const { + return PositionToIterator(0); + } + virtual Iterator* EndIterator(const Field* data) const { + return PositionToIterator(this->Size(data)); + } + virtual Iterator* CopyIterator(const Field* data, + const Iterator* iterator) const { + return const_cast(iterator); + } + virtual Iterator* AdvanceIterator(const Field* data, + Iterator* iterator) const { + return PositionToIterator(IteratorToPosition(iterator) + 1); + } + virtual bool EqualsIterator(const Field* data, + const Iterator* a, + const Iterator* b) const { + return a == b; + } + virtual void DeleteIterator(const Field* data, Iterator* iterator) const { + } + virtual const Value* GetIteratorValue(const Field* data, + const Iterator* iterator, + Value* scratch_space) const { + return Get(data, static_cast(IteratorToPosition(iterator)), + scratch_space); + } + + private: + static intptr_t IteratorToPosition(const Iterator* iterator) { + return reinterpret_cast(iterator); + } + static Iterator* PositionToIterator(intptr_t position) { + return reinterpret_cast(position); + } +}; + +// Base class for RepeatedFieldAccessor implementations that manipulates +// RepeatedField. +template +class RepeatedFieldWrapper : public RandomAccessRepeatedFieldAccessor { + public: + RepeatedFieldWrapper() {} + virtual ~RepeatedFieldWrapper() {} + virtual bool IsEmpty(const Field* data) const { + return GetRepeatedField(data)->empty(); + } + virtual int Size(const Field* data) const { + return GetRepeatedField(data)->size(); + } + virtual const Value* Get(const Field* data, int index, + Value* scratch_space) const { + return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space); + } + virtual void Clear(Field* data) const { + MutableRepeatedField(data)->Clear(); + } + virtual void Set(Field* data, int index, const Value* value) const { + MutableRepeatedField(data)->Set(index, ConvertToT(value)); + } + virtual void Add(Field* data, const Value* value) const { + MutableRepeatedField(data)->Add(ConvertToT(value)); + } + virtual void RemoveLast(Field* data) const { + MutableRepeatedField(data)->RemoveLast(); + } + virtual void SwapElements(Field* data, int index1, int index2) const { + MutableRepeatedField(data)->SwapElements(index1, index2); + } + + protected: + typedef RepeatedField RepeatedFieldType; + static const RepeatedFieldType* GetRepeatedField(const Field* data) { + return reinterpret_cast(data); + } + static RepeatedFieldType* MutableRepeatedField(Field* data) { + return reinterpret_cast(data); + } + + // Convert an object recevied by this accessor to an object to be stored in + // the underlying RepeatedField. + virtual T ConvertToT(const Value* value) const = 0; + + // Convert an object stored in RepeatedPtrField to an object that will be + // returned by this accessor. If the two objects have the same type (true + // for string fields with ctype=STRING), a pointer to the source object can + // be returned directly. Otherwise, data should be copied from value to + // scratch_space and scratch_space should be returned. + virtual const Value* ConvertFromT(const T& value, + Value* scratch_space) const = 0; +}; + +// Base class for RepeatedFieldAccessor implementations that manipulates +// RepeatedPtrField. +template +class RepeatedPtrFieldWrapper : public RandomAccessRepeatedFieldAccessor { + public: + RepeatedPtrFieldWrapper() {} + virtual ~RepeatedPtrFieldWrapper() {} + virtual bool IsEmpty(const Field* data) const { + return GetRepeatedField(data)->empty(); + } + virtual int Size(const Field* data) const { + return GetRepeatedField(data)->size(); + } + virtual const Value* Get(const Field* data, int index, + Value* scratch_space) const { + return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space); + } + virtual void Clear(Field* data) const { + MutableRepeatedField(data)->Clear(); + } + virtual void Set(Field* data, int index, const Value* value) const { + ConvertToT(value, MutableRepeatedField(data)->Mutable(index)); + } + virtual void Add(Field* data, const Value* value) const { + T* allocated = New(value); + ConvertToT(value, allocated); + MutableRepeatedField(data)->AddAllocated(allocated); + } + virtual void RemoveLast(Field* data) const { + MutableRepeatedField(data)->RemoveLast(); + } + virtual void SwapElements(Field* data, int index1, int index2) const { + MutableRepeatedField(data)->SwapElements(index1, index2); + } + + protected: + typedef RepeatedPtrField RepeatedFieldType; + static const RepeatedFieldType* GetRepeatedField(const Field* data) { + return reinterpret_cast(data); + } + static RepeatedFieldType* MutableRepeatedField(Field* data) { + return reinterpret_cast(data); + } + + // Create a new T instance. For repeated message fields, T can be specified + // as google::protobuf::Message so we can't use "new T()" directly. In that case, value + // should be a message of the same type (it's ensured by the caller) and a + // new message object will be created using it. + virtual T* New(const Value* value) const = 0; + + // Convert an object received by this accessor to an object that will be + // stored in the underlying RepeatedPtrField. + virtual void ConvertToT(const Value* value, T* result) const = 0; + + // Convert an object stored in RepeatedPtrField to an object that will be + // returned by this accessor. If the two objects have the same type (true + // for string fields with ctype=STRING), a pointer to the source object can + // be returned directly. Otherwise, data should be copied from value to + // scratch_space and scratch_space should be returned. + virtual const Value* ConvertFromT(const T& value, + Value* scratch_space) const = 0; +}; + +// Default implementations of RepeatedFieldAccessor for primitive types. +template +class RepeatedFieldPrimitiveAccessor : public RepeatedFieldWrapper { + typedef void Field; + typedef void Value; + using RepeatedFieldWrapper::MutableRepeatedField; + + public: + RepeatedFieldPrimitiveAccessor() {} + virtual ~RepeatedFieldPrimitiveAccessor() {} + virtual void Swap( + Field* data, + const internal::RepeatedFieldAccessor* other_mutator, + Field* other_data) const { + // Currently RepeatedFieldPrimitiveAccessor is the only implementation of + // RepeatedFieldAccessor for primitive types. As we are using singletons + // for these accessors, here "other_mutator" must be "this". + GOOGLE_CHECK(this == other_mutator); + MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data)); + } + + protected: + virtual T ConvertToT(const Value* value) const { + return *static_cast(value); + } + virtual const Value* ConvertFromT(const T& value, + Value* scratch_space) const { + return static_cast(&value); + } +}; + +// Default implementation of RepeatedFieldAccessor for string fields with +// ctype=STRING. +class RepeatedPtrFieldStringAccessor : public RepeatedPtrFieldWrapper { + typedef void Field; + typedef void Value; + using RepeatedFieldAccessor::Add; + + public: + RepeatedPtrFieldStringAccessor() {} + virtual ~RepeatedPtrFieldStringAccessor() {} + virtual void Swap( + Field* data, + const internal::RepeatedFieldAccessor* other_mutator, + Field* other_data) const { + if (this == other_mutator) { + MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data)); + } else { + RepeatedPtrField tmp; + tmp.Swap(MutableRepeatedField(data)); + int other_size = other_mutator->Size(other_data); + for (int i = 0; i < other_size; ++i) { + Add(data, other_mutator->Get(other_data, i)); + } + int size = Size(data); + other_mutator->Clear(other_data); + for (int i = 0; i < size; ++i) { + other_mutator->Add(other_data, tmp.Get(i)); + } + } + } + + protected: + virtual string* New(const Value*) const { + return new string(); + } + virtual void ConvertToT(const Value* value, string* result) const { + *result = *static_cast(value); + } + virtual const Value* ConvertFromT(const string& value, + Value* scratch_space) const { + return static_cast(&value); + } +}; + + +class RepeatedPtrFieldMessageAccessor + : public RepeatedPtrFieldWrapper { + typedef void Field; + typedef void Value; + + public: + RepeatedPtrFieldMessageAccessor() {} + virtual ~RepeatedPtrFieldMessageAccessor() {} + virtual void Swap( + Field* data, + const internal::RepeatedFieldAccessor* other_mutator, + Field* other_data) const { + GOOGLE_CHECK(this == other_mutator); + MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data)); + } + + protected: + virtual Message* New(const Value* value) const { + return static_cast(value)->New(); + } + virtual void ConvertToT(const Value* value, Message* result) const { + result->CopyFrom(*static_cast(value)); + } + virtual const Value* ConvertFromT(const Message& value, + Value* scratch_space) const { + return static_cast(&value); + } +}; +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__ diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index b400732f..e5aedadc 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -42,42 +42,52 @@ namespace protobuf { namespace internal { -void RepeatedPtrFieldBase::Reserve(int new_size) { - if (total_size_ >= new_size) return; - - void** old_elements = elements_; - total_size_ = max(kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); - elements_ = new void*[total_size_]; - if (old_elements != NULL) { - memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); - delete [] old_elements; +void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { + int new_size = current_size_ + extend_amount; + if (total_size_ >= new_size) { + // N.B.: rep_ is non-NULL because extend_amount is always > 0, hence + // total_size must be non-zero since it is lower-bounded by new_size. + return &rep_->elements[current_size_]; + } + Rep* old_rep = rep_; + Arena* arena = GetArenaNoVirtual(); + new_size = max(kMinRepeatedFieldAllocationSize, + max(total_size_ * 2, new_size)); + if (arena == NULL) { + rep_ = reinterpret_cast( + new char[kRepHeaderSize + sizeof(old_rep->elements[0])*new_size]); + } else { + rep_ = reinterpret_cast( + ::google::protobuf::Arena::CreateArray(arena, + kRepHeaderSize + sizeof(old_rep->elements[0])*new_size)); + } + total_size_ = new_size; + if (old_rep && old_rep->allocated_size > 0) { + memcpy(rep_->elements, old_rep->elements, + old_rep->allocated_size * sizeof(rep_->elements[0])); + rep_->allocated_size = old_rep->allocated_size; + } else { + rep_->allocated_size = 0; + } + if (arena == NULL) { + delete [] reinterpret_cast(old_rep); } + return &rep_->elements[current_size_]; } -void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { - if (this == other) return; - void** swap_elements = elements_; - int swap_current_size = current_size_; - int swap_allocated_size = allocated_size_; - int swap_total_size = total_size_; - - elements_ = other->elements_; - current_size_ = other->current_size_; - allocated_size_ = other->allocated_size_; - total_size_ = other->total_size_; - - other->elements_ = swap_elements; - other->current_size_ = swap_current_size; - other->allocated_size_ = swap_allocated_size; - other->total_size_ = swap_total_size; +void RepeatedPtrFieldBase::Reserve(int new_size) { + if (new_size > current_size_) { + InternalExtend(new_size - current_size_); + } } -string* StringTypeHandlerBase::New() { - return new string; -} -void StringTypeHandlerBase::Delete(string* value) { - delete value; +void RepeatedPtrFieldBase::CloseGap(int start, int num) { + if (rep_ == NULL) return; + // Close up a gap of "num" elements starting at offset "start". + for (int i = start + num; i < rep_->allocated_size; ++i) + rep_->elements[i - num] = rep_->elements[i]; + current_size_ -= num; + rep_->allocated_size -= num; } } // namespace internal diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 816ea684..c21ba97f 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -53,8 +53,10 @@ #include #include +#include #include #include +#include #include #include @@ -104,6 +106,7 @@ template class RepeatedField { public: RepeatedField(); + explicit RepeatedField(Arena* arena); RepeatedField(const RepeatedField& other); template RepeatedField(Iter begin, const Iter& end); @@ -153,9 +156,16 @@ class RepeatedField { Element* mutable_data(); const Element* data() const; - // Swap entire contents with "other". + // Swap entire contents with "other". If they are separate arenas then, copies + // data between each other. void Swap(RepeatedField* other); + // Swap entire contents with "other". Should be called only if the caller can + // guarantee that both repeated fields are on the same arena or are on the + // heap. Swapping between different arenas is disallowed and caught by a + // GOOGLE_DCHECK (see API docs for details). + void UnsafeArenaSwap(RepeatedField* other); + // Swap two elements. void SwapElements(int index1, int index2); @@ -172,8 +182,10 @@ class RepeatedField { iterator begin(); const_iterator begin() const; + const_iterator cbegin() const; iterator end(); const_iterator end() const; + const_iterator cend() const; // Reverse iterator support typedef std::reverse_iterator const_reverse_iterator; @@ -195,20 +207,60 @@ class RepeatedField { // sizeof(*this) int SpaceUsedExcludingSelf() const; + // Remove the element referenced by position. + iterator erase(const_iterator position); + + // Remove the elements in the range [first, last). + iterator erase(const_iterator first, const_iterator last); + + // Get the Arena on which this RepeatedField stores its elements. + ::google::protobuf::Arena* GetArena() const { + return GetArenaNoVirtual(); + } + private: static const int kInitialSize = 0; - - Element* elements_; - int current_size_; - int total_size_; + // A note on the representation here (see also comment below for + // RepeatedPtrFieldBase's struct Rep): + // + // We maintain the same sizeof(RepeatedField) as before we added arena support + // so that we do not degrade performance by bloating memory usage. Directly + // adding an arena_ element to RepeatedField is quite costly. By using + // indirection in this way, we keep the same size when the RepeatedField is + // empty (common case), and add only an 8-byte header to the elements array + // when non-empty. We make sure to place the size fields directly in the + // RepeatedField class to avoid costly cache misses due to the indirection. + int current_size_; + int total_size_; + struct Rep { + Arena* arena; + Element elements[1]; + }; + // Why not sizeof(Rep) - sizeof(Element)? Because this is not accurate w.r.t. + // trailing padding on the struct -- e.g. if Element is int, this would yield + // 12 on x86-64, not 8 as we want. + static const size_t kRepHeaderSize = sizeof(Arena*); + // Contains arena ptr and the elements array. We also keep the invariant that + // if rep_ is NULL, then arena is NULL. + Rep* rep_; + + friend class Arena; + typedef void InternalArenaConstructable_; // Move the contents of |from| into |to|, possibly clobbering |from| in the // process. For primitive types this is just a memcpy(), but it could be // specialized for non-primitive types to, say, swap each element instead. - void MoveArray(Element to[], Element from[], int size); + void MoveArray(Element* to, Element* from, int size); // Copy the elements of |from| into |to|. - void CopyArray(Element to[], const Element from[], int size); + void CopyArray(Element* to, const Element* from, int size); + + inline void InternalSwap(RepeatedField* other); + + // Internal helper expected by Arena methods. + inline Arena* GetArenaNoVirtual() const { + return (rep_ == NULL) ? NULL : rep_->arena; + } }; namespace internal { @@ -225,13 +277,48 @@ namespace internal { template ::value> struct ElementCopier { - void operator()(Element to[], const Element from[], int array_size); + void operator()(Element* to, const Element* from, int array_size); }; } // namespace internal namespace internal { +// type-traits helper for RepeatedPtrFieldBase: we only want to invoke +// arena-related "copy if on different arena" behavior if the necessary methods +// exist on the contained type. In particular, we rely on MergeFrom() existing +// as a general proxy for the fact that a copy will work, and we also provide a +// specific override for string*. +template +struct TypeImplementsMergeBehavior { + typedef char HasMerge; + typedef long HasNoMerge; + + // We accept either of: + // - void MergeFrom(const T& other) + // - bool MergeFrom(const T& other) + // + // We mangle these names a bit to avoid compatibility issues in 'unclean' + // include environments that may have, e.g., "#define test ..." (yes, this + // exists). + template + struct CheckType; + template static HasMerge Check( + CheckType*); + template static HasMerge Check( + CheckType*); + template static HasNoMerge Check(...); + + // Resovles to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. + typedef google::protobuf::internal::integral_constant(0)) == sizeof(HasMerge))> type; +}; + +template<> +struct TypeImplementsMergeBehavior< ::std::string > { + typedef google::protobuf::internal::true_type type; +}; + // This is the common base class for RepeatedPtrFields. It deals only in void* // pointers. Users should not use this interface directly. // @@ -267,6 +354,8 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers; RepeatedPtrFieldBase(); + explicit RepeatedPtrFieldBase(::google::protobuf::Arena* arena); + ~RepeatedPtrFieldBase() {} // Must be called from destructor. template @@ -280,7 +369,10 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template typename TypeHandler::Type* Mutable(int index); template - typename TypeHandler::Type* Add(); + void Delete(int index); + template + typename TypeHandler::Type* Add(typename TypeHandler::Type* prototype = NULL); + template void RemoveLast(); template @@ -290,13 +382,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template void CopyFrom(const RepeatedPtrFieldBase& other); - void CloseGap(int start, int num) { - // Close up a gap of "num" elements starting at offset "start". - for (int i = start + num; i < allocated_size_; ++i) - elements_[i - num] = elements_[i]; - current_size_ -= num; - allocated_size_ -= num; - } + void CloseGap(int start, int num); void Reserve(int new_size); @@ -311,7 +397,8 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template const typename TypeHandler::Type* const* data() const; - void Swap(RepeatedPtrFieldBase* other); + template + inline void Swap(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; void SwapElements(int index1, int index2); @@ -325,10 +412,25 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template typename TypeHandler::Type* AddFromCleared(); + template + void AddAllocated(typename TypeHandler::Type* value) { + typename TypeImplementsMergeBehavior::type t; + AddAllocatedInternal(value, t); + } + template - void AddAllocated(typename TypeHandler::Type* value); + void UnsafeArenaAddAllocated(typename TypeHandler::Type* value); + template - typename TypeHandler::Type* ReleaseLast(); + typename TypeHandler::Type* ReleaseLast() { + typename TypeImplementsMergeBehavior::type t; + return ReleaseLastInternal(t); + } + + // Releases last element and returns it, but does not do out-of-arena copy. + // And just returns the raw pointer to the contained element in the arena. + template + typename TypeHandler::Type* UnsafeArenaReleaseLast(); int ClearedCount() const; template @@ -336,13 +438,61 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template typename TypeHandler::Type* ReleaseCleared(); + protected: + inline void InternalSwap(RepeatedPtrFieldBase* other); + + template + void AddAllocatedInternal(typename TypeHandler::Type* value, + google::protobuf::internal::true_type); + template + void AddAllocatedInternal(typename TypeHandler::Type* value, + google::protobuf::internal::false_type); + + template + void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value, + Arena* value_arena, + Arena* my_arena) + GOOGLE_ATTRIBUTE_NOINLINE; + template + void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value) + GOOGLE_ATTRIBUTE_NOINLINE; + + template + typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::true_type); + template + typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::false_type); + + template + inline void SwapFallback(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_NOINLINE; + + inline Arena* GetArenaNoVirtual() const { + return arena_; + } + private: static const int kInitialSize = 0; - - void** elements_; + // A few notes on internal representation: + // + // We use an indirected approach, with struct Rep, to keep + // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support + // was added, namely, 3 8-byte machine words on x86-64. An instance of Rep is + // allocated only when the repeated field is non-empty, and it is a + // dynamically-sized struct (the header is directly followed by elements[]). + // We place arena_ and current_size_ directly in the object to avoid cache + // misses due to the indirection, because these fields are checked frequently. + // Placing all fields directly in the RepeatedPtrFieldBase instance costs + // significant performance for memory-sensitive workloads. + Arena* arena_; int current_size_; - int allocated_size_; int total_size_; + struct Rep { + int allocated_size; + void* elements[1]; + }; + static const size_t kRepHeaderSize = sizeof(Rep) - sizeof(void*); + // Contains arena ptr and the elements array. We also keep the invariant that + // if rep_ is NULL, then arena is NULL. + Rep* rep_; template static inline typename TypeHandler::Type* cast(void* element) { @@ -353,6 +503,22 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { return reinterpret_cast(element); } + // Non-templated inner function to avoid code duplication. Takes a function + // pointer to the type-specific (templated) inner allocate/merge loop. + void MergeFromInternal( + const RepeatedPtrFieldBase& other, + void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)); + + template + void MergeFromInnerLoop( + void** our_elems, void** other_elems, int length, int already_allocated); + + // Internal helper: extend array space if necessary to contain |extend_amount| + // more elements, and return a pointer to the element immediately following + // the old list of elements. This interface factors out common behavior from + // Reserve() and MergeFrom() to reduce code size. |extend_amount| must be > 0. + void** InternalExtend(int extend_amount); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase); }; @@ -360,22 +526,98 @@ template class GenericTypeHandler { public: typedef GenericType Type; - static GenericType* New() { return new GenericType; } - static void Delete(GenericType* value) { delete value; } - static void Clear(GenericType* value) { value->Clear(); } - static void Merge(const GenericType& from, GenericType* to) { + static inline GenericType* New(Arena* arena) { + return ::google::protobuf::Arena::CreateMaybeMessage( + arena, static_cast(0)); + } + // We force NewFromPrototype() and Delete() to be non-inline to reduce code + // size: else, several other methods get inlined copies of message types' + // constructors and destructors. Note that the GOOGLE_ATTRIBUTE_NOINLINE macro + // requires the 'inline' storage class here, which is somewhat confusing, but + // the compiler does the right thing. + static inline GenericType* NewFromPrototype(const GenericType* prototype, + ::google::protobuf::Arena* arena = NULL) + GOOGLE_ATTRIBUTE_NOINLINE { + return New(arena); + } + static inline void Delete(GenericType* value, Arena* arena) + GOOGLE_ATTRIBUTE_NOINLINE { + if (arena == NULL) { + delete value; + } + } + static inline ::google::protobuf::Arena* GetArena(GenericType* value) { + return ::google::protobuf::Arena::GetArena(value); + } + static inline void* GetMaybeArenaPointer(GenericType* value) { + return ::google::protobuf::Arena::GetArena(value); + } + + static inline void Clear(GenericType* value) { value->Clear(); } + static inline void Merge(const GenericType& from, GenericType* to) + GOOGLE_ATTRIBUTE_NOINLINE { to->MergeFrom(from); } - static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); } - static const Type& default_instance() { return Type::default_instance(); } + static inline int SpaceUsed(const GenericType& value) { + return value.SpaceUsed(); + } + static inline const Type& default_instance() { + return Type::default_instance(); + } }; +// Macros for specializing GenericTypeHandler for base proto types, these are +// are defined here, to allow inlining them at their callsites. +#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Inline, TypeName) \ + template<> \ + Inline TypeName* GenericTypeHandler::NewFromPrototype( \ + const TypeName* prototype, google::protobuf::Arena* arena) { \ + return prototype->New(arena); \ + } \ + template<> \ + Inline google::protobuf::Arena* GenericTypeHandler::GetArena( \ + TypeName* value) { \ + return value->GetArena(); \ + } \ + template<> \ + Inline void* GenericTypeHandler::GetMaybeArenaPointer( \ + TypeName* value) { \ + return value->GetMaybeArenaPointer(); \ + } +#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(TypeName) \ + DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(, TypeName) + +// Implements GenericTypeHandler specialization required by RepeatedPtrFields +// to work with MessageLite type. template <> inline void GenericTypeHandler::Merge( const MessageLite& from, MessageLite* to) { to->CheckTypeAndMergeFrom(from); } +DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(inline, MessageLite); + +// Declarations of the specialization as we cannot define them here, as the +// header that defines ProtocolMessage depends on types defined in this header. +#define DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(TypeName) \ + template<> \ + TypeName* GenericTypeHandler::NewFromPrototype( \ + const TypeName* prototype, google::protobuf::Arena* arena); \ + template<> \ + google::protobuf::Arena* GenericTypeHandler::GetArena( \ + TypeName* value); \ + template<> \ + void* GenericTypeHandler::GetMaybeArenaPointer( \ + TypeName* value); + +// Message specialization bodies defined in message.cc. This split is necessary +// to allow proto2-lite (which includes this header) to be independent of +// Message. +DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message); + + +#undef DECLARE_SPECIALIZATIONS_FOR_BASE_CLASSES + template <> inline const MessageLite& GenericTypeHandler::default_instance() { // Yes, the behavior of the code is undefined, but this function is only @@ -406,11 +648,28 @@ inline const Message& GenericTypeHandler::default_instance() { class LIBPROTOBUF_EXPORT StringTypeHandlerBase { public: typedef string Type; - static string* New(); - static void Delete(string* value); - static void Clear(string* value) { value->clear(); } - static void Merge(const string& from, string* to) { *to = from; } - static const Type& default_instance() { + + static inline string* New(Arena* arena) { + return Arena::Create(arena); + } + static inline string* NewFromPrototype(const string*, + ::google::protobuf::Arena* arena) { + return New(arena); + } + static inline ::google::protobuf::Arena* GetArena(string*) { + return NULL; + } + static inline void* GetMaybeArenaPointer(string* value) { + return NULL; + } + static inline void Delete(string* value, Arena* arena) { + if (arena == NULL) { + delete value; + } + } + static inline void Clear(string* value) { value->clear(); } + static inline void Merge(const string& from, string* to) { *to = from; } + static inline const Type& default_instance() { return ::google::protobuf::internal::GetEmptyString(); } }; @@ -431,6 +690,8 @@ template class RepeatedPtrField : public internal::RepeatedPtrFieldBase { public: RepeatedPtrField(); + explicit RepeatedPtrField(::google::protobuf::Arena* arena); + RepeatedPtrField(const RepeatedPtrField& other); template RepeatedPtrField(Iter begin, const Iter& end); @@ -470,9 +731,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { Element** mutable_data(); const Element* const* data() const; - // Swap entire contents with "other". + // Swap entire contents with "other". If they are on separate arenas, then + // copies data. void Swap(RepeatedPtrField* other); + // Swap entire contents with "other". Caller should guarantee that either both + // fields are on the same arena or both are on the heap. Swapping between + // different arenas with this function is disallowed and is caught via + // GOOGLE_DCHECK. + void UnsafeArenaSwap(RepeatedPtrField* other); + // Swap two elements. void SwapElements(int index1, int index2); @@ -489,8 +757,10 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { iterator begin(); const_iterator begin() const; + const_iterator cbegin() const; iterator end(); const_iterator end() const; + const_iterator cend() const; // Reverse iterator support typedef std::reverse_iterator const_reverse_iterator; @@ -529,11 +799,36 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Add an already-allocated object, passing ownership to the // RepeatedPtrField. + // + // Note that some special behavior occurs with respect to arenas: + // + // (i) if this field holds submessages, the new submessage will be copied if + // the original is in an arena and this RepeatedPtrField is either in a + // different arena, or on the heap. + // (ii) if this field holds strings, the passed-in string *must* be + // heap-allocated, not arena-allocated. There is no way to dynamically check + // this at runtime, so User Beware. void AddAllocated(Element* value); + // Remove the last element and return it, passing ownership to the caller. // Requires: size() > 0 + // + // If this RepeatedPtrField is on an arena, an object copy is required to pass + // ownership back to the user (for compatible semantics). Use + // UnsafeArenaReleaseLast() if this behavior is undesired. Element* ReleaseLast(); + // Add an already-allocated object, skipping arena-ownership checks. The user + // must guarantee that the given object is in the same arena as this + // RepeatedPtrField. + void UnsafeArenaAddAllocated(Element* value); + + // Remove the last element and return it. Works only when operating on an + // arena. The returned pointer is to the original object in the arena, hence + // has the arena's lifetime. + // Requires: current_size_ > 0 + Element* UnsafeArenaReleaseLast(); + // Extract elements with indices in the range "[start .. start+num-1]". // The caller assumes ownership of the extracted elements and is responsible // for deleting them when they are no longer needed. @@ -543,8 +838,20 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // to perform any further operations (like deletion) on these elements. // Caution: implementation also moves elements with indices [start+num ..]. // Calling this routine inside a loop can cause quadratic behavior. + // + // Memory copying behavior is identical to ReleaseLast(), described above: if + // this RepeatedPtrField is on an arena, an object copy is performed for each + // returned element, so that all returned element pointers are to + // heap-allocated copies. If this copy is not desired, the user should call + // UnsafeArenaExtractSubrange(). void ExtractSubrange(int start, int num, Element** elements); + // Identical to ExtractSubrange() described above, except that when this + // repeated field is on an arena, no object copies are performed. Instead, the + // raw object pointers are returned. Thus, if on an arena, the returned + // objects must not be freed, because they will not be heap-allocated objects. + void UnsafeArenaExtractSubrange(int start, int num, Element** elements); + // When elements are removed by calls to RemoveLast() or Clear(), they // are not actually freed. Instead, they are cleared and kept so that // they can be reused later. This can save lots of CPU time when @@ -559,12 +866,30 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Add an element to the pool of cleared objects, passing ownership to // the RepeatedPtrField. The element must be cleared prior to calling // this method. + // + // This method cannot be called when the repeated field is on an arena or when + // |value| is; both cases will trigger a GOOGLE_DCHECK-failure. void AddCleared(Element* value); // Remove a single element from the cleared pool and return it, passing // ownership to the caller. The element is guaranteed to be cleared. // Requires: ClearedCount() > 0 + // + // + // This method cannot be called when the repeated field is on an arena; doing + // so will trigger a GOOGLE_DCHECK-failure. Element* ReleaseCleared(); + // Remove the element referenced by position. + iterator erase(const_iterator position); + + // Removes the elements in the range [first, last). + iterator erase(const_iterator first, const_iterator last); + + // Gets the arena on which this RepeatedPtrField stores its elements. + ::google::protobuf::Arena* GetArena() const { + return GetArenaNoVirtual(); + } + protected: // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only // subclass it in one place as a hack for compatibility with proto1. The @@ -572,31 +897,61 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // methods on RepeatedPtrFieldBase. class TypeHandler; + // Internal arena accessor expected by helpers in Arena. + inline Arena* GetArenaNoVirtual() const; + + private: + // Implementations for ExtractSubrange(). The copying behavior must be + // included only if the type supports the necessary operations (e.g., + // MergeFrom()), so we must resolve this at compile time. ExtractSubrange() + // uses SFINAE to choose one of the below implementations. + void ExtractSubrangeInternal(int start, int num, Element** elements, + google::protobuf::internal::true_type); + void ExtractSubrangeInternal(int start, int num, Element** elements, + google::protobuf::internal::false_type); + + friend class Arena; + typedef void InternalArenaConstructable_; + }; // implementation ==================================================== template inline RepeatedField::RepeatedField() - : elements_(NULL), - current_size_(0), - total_size_(kInitialSize) { + : current_size_(0), + total_size_(0), + rep_(NULL) { +} + +template +inline RepeatedField::RepeatedField(Arena* arena) + : current_size_(0), + total_size_(0), + rep_(NULL) { + // In case arena is NULL, then we do not create rep_, as code has an invariant + // `rep_ == NULL then arena == NULL`. + if (arena != NULL) { + rep_ = reinterpret_cast( + ::google::protobuf::Arena::CreateArray(arena, kRepHeaderSize)); + rep_->arena = arena; + } } template inline RepeatedField::RepeatedField(const RepeatedField& other) - : elements_(NULL), - current_size_(0), - total_size_(kInitialSize) { + : current_size_(0), + total_size_(0), + rep_(NULL) { CopyFrom(other); } template template -inline RepeatedField::RepeatedField(Iter begin, const Iter& end) - : elements_(NULL), - current_size_(0), - total_size_(kInitialSize) { +RepeatedField::RepeatedField(Iter begin, const Iter& end) + : current_size_(0), + total_size_(0), + rep_(NULL) { int reserve = internal::CalculateReserve(begin, end); if (reserve != -1) { Reserve(reserve); @@ -612,7 +967,20 @@ inline RepeatedField::RepeatedField(Iter begin, const Iter& end) template RepeatedField::~RepeatedField() { - delete [] elements_; + // See explanation in Reserve(): we need to invoke destructors here for the + // case that Element has a non-trivial destructor. If Element has a trivial + // destructor (for example, if it's a primitive type, like int32), this entire + // loop will be removed by the optimizer. + if (rep_ != NULL) { + Element* e = &rep_->elements[0]; + Element* limit = &rep_->elements[total_size_]; + for (; e < limit; e++) { + e->Element::~Element(); + } + if (rep_->arena == NULL) { + delete[] reinterpret_cast(rep_); + } + } } template @@ -640,22 +1008,23 @@ inline int RepeatedField::Capacity() const { template inline void RepeatedField::AddAlreadyReserved(const Element& value) { - GOOGLE_DCHECK_LT(size(), Capacity()); - elements_[current_size_++] = value; + GOOGLE_DCHECK_LT(current_size_, total_size_); + rep_->elements[current_size_++] = value; } template inline Element* RepeatedField::AddAlreadyReserved() { - GOOGLE_DCHECK_LT(size(), Capacity()); - return &elements_[current_size_++]; + GOOGLE_DCHECK_LT(current_size_, total_size_); + return &rep_->elements[current_size_++]; } template inline void RepeatedField::Resize(int new_size, const Element& value) { GOOGLE_DCHECK_GE(new_size, 0); - if (new_size > size()) { + if (new_size > current_size_) { Reserve(new_size); - std::fill(&elements_[current_size_], &elements_[new_size], value); + std::fill(&rep_->elements[current_size_], + &rep_->elements[new_size], value); } current_size_ = new_size; } @@ -663,40 +1032,40 @@ inline void RepeatedField::Resize(int new_size, const Element& value) { template inline const Element& RepeatedField::Get(int index) const { GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, size()); - return elements_[index]; + GOOGLE_DCHECK_LT(index, current_size_); + return rep_->elements[index]; } template inline Element* RepeatedField::Mutable(int index) { GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, size()); - return elements_ + index; + GOOGLE_DCHECK_LT(index, current_size_); + return &rep_->elements[index]; } template inline void RepeatedField::Set(int index, const Element& value) { GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, size()); - elements_[index] = value; + GOOGLE_DCHECK_LT(index, current_size_); + rep_->elements[index] = value; } template inline void RepeatedField::Add(const Element& value) { if (current_size_ == total_size_) Reserve(total_size_ + 1); - elements_[current_size_++] = value; + rep_->elements[current_size_++] = value; } template inline Element* RepeatedField::Add() { if (current_size_ == total_size_) Reserve(total_size_ + 1); - return &elements_[current_size_++]; + return &rep_->elements[current_size_++]; } template inline void RepeatedField::RemoveLast() { GOOGLE_DCHECK_GT(current_size_, 0); - --current_size_; + current_size_--; } template @@ -704,7 +1073,7 @@ void RepeatedField::ExtractSubrange( int start, int num, Element* elements) { GOOGLE_DCHECK_GE(start, 0); GOOGLE_DCHECK_GE(num, 0); - GOOGLE_DCHECK_LE(start + num, this->size()); + GOOGLE_DCHECK_LE(start + num, this->current_size_); // Save the values of the removed elements if requested. if (elements != NULL) { @@ -714,9 +1083,9 @@ void RepeatedField::ExtractSubrange( // Slide remaining elements down to fill the gap. if (num > 0) { - for (int i = start + num; i < this->size(); ++i) + for (int i = start + num; i < this->current_size_; ++i) this->Set(i - num, this->Get(i)); - this->Truncate(this->size() - num); + this->Truncate(this->current_size_ - num); } } @@ -730,7 +1099,8 @@ inline void RepeatedField::MergeFrom(const RepeatedField& other) { GOOGLE_CHECK_NE(&other, this); if (other.current_size_ != 0) { Reserve(current_size_ + other.current_size_); - CopyArray(elements_ + current_size_, other.elements_, other.current_size_); + CopyArray(rep_->elements + current_size_, + other.rep_->elements, other.current_size_); current_size_ += other.current_size_; } } @@ -742,63 +1112,99 @@ inline void RepeatedField::CopyFrom(const RepeatedField& other) { MergeFrom(other); } +template +inline typename RepeatedField::iterator RepeatedField::erase( + const_iterator position) { + return erase(position, position + 1); +} + +template +inline typename RepeatedField::iterator RepeatedField::erase( + const_iterator first, const_iterator last) { + size_type first_offset = first - cbegin(); + Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin()); + return begin() + first_offset; +} + template inline Element* RepeatedField::mutable_data() { - return elements_; + return rep_ ? rep_->elements : NULL; } template inline const Element* RepeatedField::data() const { - return elements_; + return rep_ ? rep_->elements : NULL; } +template +inline void RepeatedField::InternalSwap(RepeatedField* other) { + std::swap(rep_, other->rep_); + std::swap(current_size_, other->current_size_); + std::swap(total_size_, other->total_size_); +} + template void RepeatedField::Swap(RepeatedField* other) { if (this == other) return; - Element* swap_elements = elements_; - int swap_current_size = current_size_; - int swap_total_size = total_size_; - - elements_ = other->elements_; - current_size_ = other->current_size_; - total_size_ = other->total_size_; + if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) { + InternalSwap(other); + } else { + RepeatedField temp(other->GetArenaNoVirtual()); + temp.MergeFrom(*this); + CopyFrom(*other); + other->UnsafeArenaSwap(&temp); + } +} - other->elements_ = swap_elements; - other->current_size_ = swap_current_size; - other->total_size_ = swap_total_size; +template +void RepeatedField::UnsafeArenaSwap(RepeatedField* other) { + if (this == other) return; + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + InternalSwap(other); } template void RepeatedField::SwapElements(int index1, int index2) { using std::swap; // enable ADL with fallback - swap(elements_[index1], elements_[index2]); + swap(rep_->elements[index1], rep_->elements[index2]); } template inline typename RepeatedField::iterator RepeatedField::begin() { - return elements_; + return rep_ ? rep_->elements : NULL; } template inline typename RepeatedField::const_iterator RepeatedField::begin() const { - return elements_; + return rep_ ? rep_->elements : NULL; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::cbegin() const { + return rep_ ? rep_->elements : NULL; } template inline typename RepeatedField::iterator RepeatedField::end() { - return elements_ + current_size_; + return rep_ ? rep_->elements + current_size_ : NULL; } template inline typename RepeatedField::const_iterator RepeatedField::end() const { - return elements_ + current_size_; + return rep_ ? rep_->elements + current_size_ : NULL; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::cend() const { + return rep_ ? rep_->elements + current_size_ : NULL; } template inline int RepeatedField::SpaceUsedExcludingSelf() const { - return (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0; + return rep_ ? + (total_size_ * sizeof(Element) + kRepHeaderSize) : 0; } // Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant @@ -806,32 +1212,66 @@ inline int RepeatedField::SpaceUsedExcludingSelf() const { template void RepeatedField::Reserve(int new_size) { if (total_size_ >= new_size) return; - - Element* old_elements = elements_; - total_size_ = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); - elements_ = new Element[total_size_]; - if (old_elements != NULL) { - MoveArray(elements_, old_elements, current_size_); - delete [] old_elements; + Rep* old_rep = rep_; + Arena* arena = GetArenaNoVirtual(); + new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, + max(total_size_ * 2, new_size)); + if (arena == NULL) { + rep_ = reinterpret_cast( + new char[kRepHeaderSize + sizeof(Element)*new_size]); + } else { + rep_ = reinterpret_cast( + ::google::protobuf::Arena::CreateArray(arena, + kRepHeaderSize + sizeof(Element)*new_size)); + } + rep_->arena = arena; + total_size_ = new_size; + // Invoke placement-new on newly allocated elements. We shouldn't have to do + // this, since Element is supposed to be POD, but a previous version of this + // code allocated storage with "new Element[size]" and some code uses + // RepeatedField with non-POD types, relying on constructor invocation. If + // Element has a trivial constructor (e.g., int32), gcc (tested with -O2) + // completely removes this loop because the loop body is empty, so this has no + // effect unless its side-effects are required for correctness. + // Note that we do this before MoveArray() below because Element's copy + // assignment implementation will want an initialized instance first. + Element* e = &rep_->elements[0]; + Element* limit = &rep_->elements[total_size_]; + for (; e < limit; e++) { + new (e) Element(); + } + if (current_size_ > 0) { + MoveArray(rep_->elements, old_rep->elements, current_size_); + } + // Likewise, we need to invoke destructors on the old array. If Element has no + // destructor, this loop will disappear. + e = &old_rep->elements[0]; + limit = &old_rep->elements[current_size_]; + for (; e < limit; e++) { + e->Element::~Element(); + } + if (arena == NULL) { + delete[] reinterpret_cast(old_rep); } } template inline void RepeatedField::Truncate(int new_size) { GOOGLE_DCHECK_LE(new_size, current_size_); - current_size_ = new_size; + if (current_size_ > 0) { + current_size_ = new_size; + } } template inline void RepeatedField::MoveArray( - Element to[], Element from[], int array_size) { + Element* to, Element* from, int array_size) { CopyArray(to, from, array_size); } template inline void RepeatedField::CopyArray( - Element to[], const Element from[], int array_size) { + Element* to, const Element* from, int array_size) { internal::ElementCopier()(to, from, array_size); } @@ -839,13 +1279,13 @@ namespace internal { template void ElementCopier::operator()( - Element to[], const Element from[], int array_size) { + Element* to, const Element* from, int array_size) { std::copy(from, from + array_size, to); } template struct ElementCopier { - void operator()(Element to[], const Element from[], int array_size) { + void operator()(Element* to, const Element* from, int array_size) { memcpy(to, from, array_size * sizeof(Element)); } }; @@ -858,18 +1298,55 @@ struct ElementCopier { namespace internal { inline RepeatedPtrFieldBase::RepeatedPtrFieldBase() - : elements_(NULL), + : arena_(NULL), current_size_(0), - allocated_size_(0), - total_size_(kInitialSize) { + total_size_(0), + rep_(NULL) { +} + +inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(::google::protobuf::Arena* arena) + : arena_(arena), + current_size_(0), + total_size_(0), + rep_(NULL) { } template void RepeatedPtrFieldBase::Destroy() { - for (int i = 0; i < allocated_size_; i++) { - TypeHandler::Delete(cast(elements_[i])); + if (rep_ != NULL) { + for (int i = 0; i < rep_->allocated_size; i++) { + TypeHandler::Delete(cast(rep_->elements[i]), arena_); + } + if (arena_ == NULL) { + delete [] reinterpret_cast(rep_); + } } - delete [] elements_; + rep_ = NULL; +} + +template +inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { + if (other->GetArenaNoVirtual() == GetArenaNoVirtual()) { + InternalSwap(other); + } else { + SwapFallback(other); + } +} + +template +inline void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { + GOOGLE_DCHECK(other->GetArenaNoVirtual() != GetArenaNoVirtual()); + + // Copy semantics in this case. We try to improve efficiency by placing the + // temporary on |other|'s arena so that messages are copied cross-arena only + // once, not twice. + RepeatedPtrFieldBase temp(other->GetArenaNoVirtual()); + temp.MergeFrom(*this); + this->Clear(); + this->MergeFrom(*other); + other->Clear(); + other->InternalSwap(&temp); + temp.Destroy(); // Frees rep_ if `other` had no arena. } inline bool RepeatedPtrFieldBase::empty() const { @@ -884,8 +1361,8 @@ template inline const typename TypeHandler::Type& RepeatedPtrFieldBase::Get(int index) const { GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, size()); - return *cast(elements_[index]); + GOOGLE_DCHECK_LT(index, current_size_); + return *cast(rep_->elements[index]); } @@ -893,42 +1370,106 @@ template inline typename TypeHandler::Type* RepeatedPtrFieldBase::Mutable(int index) { GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, size()); - return cast(elements_[index]); + GOOGLE_DCHECK_LT(index, current_size_); + return cast(rep_->elements[index]); } template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() { - if (current_size_ < allocated_size_) { - return cast(elements_[current_size_++]); - } - if (allocated_size_ == total_size_) Reserve(total_size_ + 1); - typename TypeHandler::Type* result = TypeHandler::New(); - ++allocated_size_; - elements_[current_size_++] = result; +inline void RepeatedPtrFieldBase::Delete(int index) { + GOOGLE_DCHECK_GE(index, 0); + GOOGLE_DCHECK_LT(index, current_size_); + TypeHandler::Delete(cast(rep_->elements[index]), arena_); +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add( + typename TypeHandler::Type* prototype) { + if (rep_ != NULL && current_size_ < rep_->allocated_size) { + return cast(rep_->elements[current_size_++]); + } + if (!rep_ || rep_->allocated_size == total_size_) { + Reserve(total_size_ + 1); + } + ++rep_->allocated_size; + typename TypeHandler::Type* result = + TypeHandler::NewFromPrototype(prototype, arena_); + rep_->elements[current_size_++] = result; return result; } template inline void RepeatedPtrFieldBase::RemoveLast() { GOOGLE_DCHECK_GT(current_size_, 0); - TypeHandler::Clear(cast(elements_[--current_size_])); + TypeHandler::Clear(cast(rep_->elements[--current_size_])); } template void RepeatedPtrFieldBase::Clear() { - for (int i = 0; i < current_size_; i++) { - TypeHandler::Clear(cast(elements_[i])); + const int n = current_size_; + GOOGLE_DCHECK_GE(n, 0); + if (n > 0) { + void* const* elements = raw_data(); + int i = 0; + do { + TypeHandler::Clear(cast(elements[i++])); + } while (i < n); + current_size_ = 0; } - current_size_ = 0; } +// To avoid unnecessary code duplication and reduce binary size, we use a +// layered approach to implementing MergeFrom(). The toplevel method is +// templated, so we get a small thunk per concrete message type in the binary. +// This calls a shared implementation with most of the logic, passing a function +// pointer to another type-specific piece of code that calls the object-allocate +// and merge handlers. template inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { - GOOGLE_CHECK_NE(&other, this); - Reserve(current_size_ + other.current_size_); - for (int i = 0; i < other.current_size_; i++) { - TypeHandler::Merge(other.template Get(i), Add()); + GOOGLE_DCHECK_NE(&other, this); + if (other.current_size_ == 0) return; + MergeFromInternal( + other, &RepeatedPtrFieldBase::MergeFromInnerLoop); +} + +inline void RepeatedPtrFieldBase::MergeFromInternal( + const RepeatedPtrFieldBase& other, + void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)) { + // Note: wrapper has already guaranteed that other.rep_ != NULL here. + int other_size = other.current_size_; + void** other_elements = other.rep_->elements; + void** new_elements = InternalExtend(other_size); + int allocated_elems = rep_->allocated_size - current_size_; + (this->*inner_loop)(new_elements, other_elements, + other_size, allocated_elems); + current_size_ += other_size; + if (rep_->allocated_size < current_size_) { + rep_->allocated_size = current_size_; + } +} + +// Merges other_elems to our_elems. +template +void RepeatedPtrFieldBase::MergeFromInnerLoop( + void** our_elems, void** other_elems, int length, int already_allocated) { + // Split into two loops, over ranges [0, allocated) and [allocated, length), + // to avoid a branch within the loop. + for (int i = 0; i < already_allocated && i < length; i++) { + // Already allocated: use existing element. + typename TypeHandler::Type* other_elem = + reinterpret_cast(other_elems[i]); + typename TypeHandler::Type* new_elem = + reinterpret_cast(our_elems[i]); + TypeHandler::Merge(*other_elem, new_elem); + } + Arena* arena = GetArenaNoVirtual(); + for (int i = already_allocated; i < length; i++) { + // Not allocated: alloc a new element first, then merge it. + typename TypeHandler::Type* other_elem = + reinterpret_cast(other_elems[i]); + typename TypeHandler::Type* new_elem = + TypeHandler::NewFromPrototype(other_elem, arena); + TypeHandler::Merge(*other_elem, new_elem); + our_elems[i] = new_elem; } } @@ -944,18 +1485,18 @@ inline int RepeatedPtrFieldBase::Capacity() const { } inline void* const* RepeatedPtrFieldBase::raw_data() const { - return elements_; + return rep_ ? rep_->elements : NULL; } inline void** RepeatedPtrFieldBase::raw_mutable_data() const { - return elements_; + return rep_ ? const_cast(rep_->elements) : NULL; } template inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this // method entirely. - return reinterpret_cast(elements_); + return reinterpret_cast(raw_mutable_data()); } template @@ -963,89 +1504,212 @@ inline const typename TypeHandler::Type* const* RepeatedPtrFieldBase::data() const { // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this // method entirely. - return reinterpret_cast(elements_); + return reinterpret_cast(raw_data()); } inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { using std::swap; // enable ADL with fallback - swap(elements_[index1], elements_[index2]); + swap(rep_->elements[index1], rep_->elements[index2]); } template inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const { - int allocated_bytes = - (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0; - for (int i = 0; i < allocated_size_; ++i) { - allocated_bytes += TypeHandler::SpaceUsed(*cast(elements_[i])); + int allocated_bytes = total_size_ * sizeof(void*); + if (rep_ != NULL) { + for (int i = 0; i < rep_->allocated_size; ++i) { + allocated_bytes += TypeHandler::SpaceUsed( + *cast(rep_->elements[i])); + } + allocated_bytes += kRepHeaderSize; } return allocated_bytes; } template inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { - if (current_size_ < allocated_size_) { - return cast(elements_[current_size_++]); + if (rep_ != NULL && current_size_ < rep_->allocated_size) { + return cast(rep_->elements[current_size_++]); } else { return NULL; } } +// AddAllocated version that implements arena-safe copying behavior. template -void RepeatedPtrFieldBase::AddAllocated( +void RepeatedPtrFieldBase::AddAllocatedInternal( + typename TypeHandler::Type* value, + google::protobuf::internal::true_type) { + Arena* element_arena = reinterpret_cast( + TypeHandler::GetMaybeArenaPointer(value)); + Arena* arena = GetArenaNoVirtual(); + if (arena == element_arena && rep_ && + rep_->allocated_size < total_size_) { + // Fast path: underlying arena representation (tagged pointer) is equal to + // our arena pointer, and we can add to array without resizing it (at least + // one slot that is not allocated). + void** elems = rep_->elements; + if (current_size_ < rep_->allocated_size) { + // Make space at [current] by moving first allocated element to end of + // allocated list. + elems[rep_->allocated_size] = elems[current_size_]; + } + elems[current_size_] = value; + current_size_ = current_size_ + 1; + rep_->allocated_size = rep_->allocated_size + 1; + return; + } else { + AddAllocatedSlowWithCopy( + value, TypeHandler::GetArena(value), arena); + } +} + +// Slowpath handles all cases, copying if necessary. +template +void RepeatedPtrFieldBase::AddAllocatedSlowWithCopy( + // Pass value_arena and my_arena to avoid duplicate virtual call (value) or + // load (mine). + typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) { + // Ensure that either the value is in the same arena, or if not, we do the + // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy + // it to our arena/heap (otherwise). + if (my_arena != NULL && value_arena == NULL) { + my_arena->Own(value); + } else if (my_arena != value_arena) { + typename TypeHandler::Type* new_value = + TypeHandler::NewFromPrototype(value, my_arena); + TypeHandler::Merge(*value, new_value); + TypeHandler::Delete(value, value_arena); + value = new_value; + } + + UnsafeArenaAddAllocated(value); +} + +// AddAllocated version that does not implement arena-safe copying behavior. +template +void RepeatedPtrFieldBase::AddAllocatedInternal( + typename TypeHandler::Type* value, + google::protobuf::internal::false_type) { + if (rep_ && rep_->allocated_size < total_size_) { + // Fast path: underlying arena representation (tagged pointer) is equal to + // our arena pointer, and we can add to array without resizing it (at least + // one slot that is not allocated). + void** elems = rep_->elements; + if (current_size_ < rep_->allocated_size) { + // Make space at [current] by moving first allocated element to end of + // allocated list. + elems[rep_->allocated_size] = elems[current_size_]; + } + elems[current_size_] = value; + current_size_ = current_size_ + 1; + ++rep_->allocated_size; + return; + } else { + UnsafeArenaAddAllocated(value); + } +} + +template +void RepeatedPtrFieldBase::UnsafeArenaAddAllocated( typename TypeHandler::Type* value) { // Make room for the new pointer. - if (current_size_ == total_size_) { + if (!rep_ || current_size_ == total_size_) { // The array is completely full with no cleared objects, so grow it. Reserve(total_size_ + 1); - ++allocated_size_; - } else if (allocated_size_ == total_size_) { + ++rep_->allocated_size; + } else if (rep_->allocated_size == total_size_) { // There is no more space in the pointer array because it contains some // cleared objects awaiting reuse. We don't want to grow the array in this // case because otherwise a loop calling AddAllocated() followed by Clear() // would leak memory. - TypeHandler::Delete(cast(elements_[current_size_])); - } else if (current_size_ < allocated_size_) { + TypeHandler::Delete( + cast(rep_->elements[current_size_]), arena_); + } else if (current_size_ < rep_->allocated_size) { // We have some cleared objects. We don't care about their order, so we // can just move the first one to the end to make space. - elements_[allocated_size_] = elements_[current_size_]; - ++allocated_size_; + rep_->elements[rep_->allocated_size] = rep_->elements[current_size_]; + ++rep_->allocated_size; } else { // There are no cleared objects. - ++allocated_size_; + ++rep_->allocated_size; + } + + rep_->elements[current_size_++] = value; +} + +// ReleaseLast() for types that implement merge/copy behavior. +template +inline typename TypeHandler::Type* +RepeatedPtrFieldBase::ReleaseLastInternal(google::protobuf::internal::true_type) { + // First, release an element. + typename TypeHandler::Type* result = UnsafeArenaReleaseLast(); + // Now perform a copy if we're on an arena. + Arena* arena = GetArenaNoVirtual(); + if (arena == NULL) { + return result; + } else { + typename TypeHandler::Type* new_result = + TypeHandler::NewFromPrototype(result, NULL); + TypeHandler::Merge(*result, new_result); + return new_result; } +} - elements_[current_size_++] = value; +// ReleaseLast() for types that *do not* implement merge/copy behavior -- this +// is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if we're on +// an arena, since the user really should implement the copy operation in this +// case. +template +inline typename TypeHandler::Type* +RepeatedPtrFieldBase::ReleaseLastInternal(google::protobuf::internal::false_type) { + GOOGLE_DCHECK(GetArenaNoVirtual() == NULL) + << "ReleaseLast() called on a RepeatedPtrField that is on an arena, " + << "with a type that does not implement MergeFrom. This is unsafe; " + << "please implement MergeFrom for your type."; + return UnsafeArenaReleaseLast(); } template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { +inline typename TypeHandler::Type* + RepeatedPtrFieldBase::UnsafeArenaReleaseLast() { GOOGLE_DCHECK_GT(current_size_, 0); typename TypeHandler::Type* result = - cast(elements_[--current_size_]); - --allocated_size_; - if (current_size_ < allocated_size_) { + cast(rep_->elements[--current_size_]); + --rep_->allocated_size; + if (current_size_ < rep_->allocated_size) { // There are cleared elements on the end; replace the removed element // with the last allocated element. - elements_[current_size_] = elements_[allocated_size_]; + rep_->elements[current_size_] = rep_->elements[rep_->allocated_size]; } return result; } inline int RepeatedPtrFieldBase::ClearedCount() const { - return allocated_size_ - current_size_; + return rep_ ? (rep_->allocated_size - current_size_) : 0; } template inline void RepeatedPtrFieldBase::AddCleared( typename TypeHandler::Type* value) { - if (allocated_size_ == total_size_) Reserve(total_size_ + 1); - elements_[allocated_size_++] = value; + GOOGLE_DCHECK(GetArenaNoVirtual() == NULL) + << "AddCleared() can only be used on a RepeatedPtrField not on an arena."; + GOOGLE_DCHECK(TypeHandler::GetArena(value) == NULL) + << "AddCleared() can only accept values not on an arena."; + if (!rep_ || rep_->allocated_size == total_size_) { + Reserve(total_size_ + 1); + } + rep_->elements[rep_->allocated_size++] = value; } template inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { - GOOGLE_DCHECK_GT(allocated_size_, current_size_); - return cast(elements_[--allocated_size_]); + GOOGLE_DCHECK(GetArenaNoVirtual() == NULL) + << "ReleaseCleared() can only be used on a RepeatedPtrField not on " + << "an arena."; + GOOGLE_DCHECK(GetArenaNoVirtual() == NULL); + GOOGLE_DCHECK(rep_ != NULL); + GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_); + return cast(rep_->elements[--rep_->allocated_size]); } } // namespace internal @@ -1064,12 +1728,17 @@ class RepeatedPtrField::TypeHandler template -inline RepeatedPtrField::RepeatedPtrField() {} +inline RepeatedPtrField::RepeatedPtrField() + : RepeatedPtrFieldBase() {} + +template +inline RepeatedPtrField::RepeatedPtrField(::google::protobuf::Arena* arena) : + RepeatedPtrFieldBase(arena) {} template inline RepeatedPtrField::RepeatedPtrField( const RepeatedPtrField& other) - : RepeatedPtrFieldBase() { + : RepeatedPtrFieldBase() { CopyFrom(other); } @@ -1135,14 +1804,25 @@ inline void RepeatedPtrField::DeleteSubrange(int start, int num) { GOOGLE_DCHECK_GE(start, 0); GOOGLE_DCHECK_GE(num, 0); GOOGLE_DCHECK_LE(start + num, size()); - for (int i = 0; i < num; ++i) - delete RepeatedPtrFieldBase::Mutable(start + i); + for (int i = 0; i < num; ++i) { + RepeatedPtrFieldBase::Delete(start + i); + } ExtractSubrange(start, num, NULL); } template inline void RepeatedPtrField::ExtractSubrange( int start, int num, Element** elements) { + typename internal::TypeImplementsMergeBehavior< + typename TypeHandler::Type>::type t; + ExtractSubrangeInternal(start, num, elements, t); +} + +// ExtractSubrange() implementation for types that implement merge/copy +// behavior. +template +inline void RepeatedPtrField::ExtractSubrangeInternal( + int start, int num, Element** elements, google::protobuf::internal::true_type) { GOOGLE_DCHECK_GE(start, 0); GOOGLE_DCHECK_GE(num, 0); GOOGLE_DCHECK_LE(start + num, size()); @@ -1150,8 +1830,55 @@ inline void RepeatedPtrField::ExtractSubrange( if (num > 0) { // Save the values of the removed elements if requested. if (elements != NULL) { - for (int i = 0; i < num; ++i) + if (GetArenaNoVirtual() != NULL) { + // If we're on an arena, we perform a copy for each element so that the + // returned elements are heap-allocated. + for (int i = 0; i < num; ++i) { + Element* element = RepeatedPtrFieldBase:: + Mutable(i + start); + typename TypeHandler::Type* new_value = + TypeHandler::NewFromPrototype(element, NULL); + TypeHandler::Merge(*element, new_value); + elements[i] = new_value; + } + } else { + for (int i = 0; i < num; ++i) { + elements[i] = RepeatedPtrFieldBase::Mutable(i + start); + } + } + } + CloseGap(start, num); + } +} + +// ExtractSubrange() implementation for types that do not implement merge/copy +// behavior. +template +inline void RepeatedPtrField::ExtractSubrangeInternal( + int start, int num, Element** elements, google::protobuf::internal::false_type) { + // This case is identical to UnsafeArenaExtractSubrange(). However, since + // ExtractSubrange() must return heap-allocated objects by contract, and we + // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that + // we are not on an arena. + GOOGLE_DCHECK(GetArenaNoVirtual() == NULL) + << "ExtractSubrange() when arena is non-NULL is only supported when " + << "the Element type supplies a MergeFrom() operation to make copies."; + UnsafeArenaExtractSubrange(start, num, elements); +} + +template +inline void RepeatedPtrField::UnsafeArenaExtractSubrange( + int start, int num, Element** elements) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + + if (num > 0) { + // Save the values of the removed elements if requested. + if (elements != NULL) { + for (int i = 0; i < num; ++i) { elements[i] = RepeatedPtrFieldBase::Mutable(i + start); + } } CloseGap(start, num); } @@ -1174,6 +1901,21 @@ inline void RepeatedPtrField::CopyFrom( RepeatedPtrFieldBase::CopyFrom(other); } +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::erase(const_iterator position) { + return erase(position, position + 1); +} + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::erase(const_iterator first, const_iterator last) { + size_type pos_offset = std::distance(cbegin(), first); + size_type last_offset = std::distance(cbegin(), last); + DeleteSubrange(pos_offset, last_offset - pos_offset); + return begin() + pos_offset; +} + template inline Element** RepeatedPtrField::mutable_data() { return RepeatedPtrFieldBase::mutable_data(); @@ -1185,15 +1927,31 @@ inline const Element* const* RepeatedPtrField::data() const { } template -void RepeatedPtrField::Swap(RepeatedPtrField* other) { - RepeatedPtrFieldBase::Swap(other); +inline void RepeatedPtrField::Swap(RepeatedPtrField* other) { + if (this == other) + return; + RepeatedPtrFieldBase::Swap(other); } template -void RepeatedPtrField::SwapElements(int index1, int index2) { +inline void RepeatedPtrField::UnsafeArenaSwap( + RepeatedPtrField* other) { + GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual()); + if (this == other) + return; + RepeatedPtrFieldBase::InternalSwap(other); +} + +template +inline void RepeatedPtrField::SwapElements(int index1, int index2) { RepeatedPtrFieldBase::SwapElements(index1, index2); } +template +inline Arena* RepeatedPtrField::GetArenaNoVirtual() const { + return RepeatedPtrFieldBase::GetArenaNoVirtual(); +} + template inline int RepeatedPtrField::SpaceUsedExcludingSelf() const { return RepeatedPtrFieldBase::SpaceUsedExcludingSelf(); @@ -1204,11 +1962,20 @@ inline void RepeatedPtrField::AddAllocated(Element* value) { RepeatedPtrFieldBase::AddAllocated(value); } +template +inline void RepeatedPtrField::UnsafeArenaAddAllocated(Element* value) { + RepeatedPtrFieldBase::UnsafeArenaAddAllocated(value); +} + template inline Element* RepeatedPtrField::ReleaseLast() { return RepeatedPtrFieldBase::ReleaseLast(); } +template +inline Element* RepeatedPtrField::UnsafeArenaReleaseLast() { + return RepeatedPtrFieldBase::UnsafeArenaReleaseLast(); +} template inline int RepeatedPtrField::ClearedCount() const { @@ -1423,6 +2190,12 @@ class RepeatedPtrOverPtrsIterator VoidPtr* it_; }; +void RepeatedPtrFieldBase::InternalSwap(RepeatedPtrFieldBase* other) { + std::swap(rep_, other->rep_); + std::swap(current_size_, other->current_size_); + std::swap(total_size_, other->total_size_); +} + } // namespace internal template @@ -1436,6 +2209,11 @@ RepeatedPtrField::begin() const { return iterator(raw_data()); } template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::cbegin() const { + return begin(); +} +template inline typename RepeatedPtrField::iterator RepeatedPtrField::end() { return iterator(raw_data() + size()); @@ -1445,6 +2223,11 @@ inline typename RepeatedPtrField::const_iterator RepeatedPtrField::end() const { return iterator(raw_data() + size()); } +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::cend() const { + return end(); +} template inline typename RepeatedPtrField::pointer_iterator diff --git a/src/google/protobuf/repeated_field_reflection.h b/src/google/protobuf/repeated_field_reflection.h new file mode 100644 index 00000000..08dfa7a5 --- /dev/null +++ b/src/google/protobuf/repeated_field_reflection.h @@ -0,0 +1,335 @@ +// 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. + +// This header file is protobuf internal. Users should not include this +// file directly. +#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ +#define GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ + +#include +#ifndef _SHARED_PTR_H +#include +#endif + +namespace google { +namespace protobuf { +namespace internal { +// Interfaces used to implement reflection RepeatedFieldRef API. +// Reflection::GetRepeatedAccessor() should return a pointer to an singleton +// object that implements the below interface. +// +// This interface passes/returns values using void pointers. The actual type +// of the value depends on the field's cpp_type. Following is a mapping from +// cpp_type to the type that should be used in this interface: +// +// field->cpp_type() T Actual type of void* +// CPPTYPE_INT32 int32 int32 +// CPPTYPE_UINT32 uint32 uint32 +// CPPTYPE_INT64 int64 int64 +// CPPTYPE_UINT64 uint64 uint64 +// CPPTYPE_DOUBLE double double +// CPPTYPE_FLOAT float float +// CPPTYPE_BOOL bool bool +// CPPTYPE_ENUM generated enum type int32 +// CPPTYPE_STRING string string +// CPPTYPE_MESSAGE generated message type google::protobuf::Message +// or google::protobuf::Message +// +// Note that for enums we use int32 in the interface. +// +// You can map from T to the actual type using RefTypeTraits: +// typedef RefTypeTraits::AccessorValueType ActualType; +class LIBPROTOBUF_EXPORT RepeatedFieldAccessor { + public: + // Typedefs for clarity. + typedef void Field; + typedef void Value; + typedef void Iterator; + + virtual ~RepeatedFieldAccessor(); + virtual bool IsEmpty(const Field* data) const = 0; + virtual int Size(const Field* data) const = 0; + // Depends on the underlying representation of the repeated field, this + // method can return a pointer to the underlying object if such an object + // exists, or fill the data into scratch_space and return scratch_space. + // Callers of this method must ensure scratch_space is a valid pointer + // to a mutable object of the correct type. + virtual const Value* Get( + const Field* data, int index, Value* scratch_space) const = 0; + + virtual void Clear(Field* data) const = 0; + virtual void Set(Field* data, int index, const Value* value) const = 0; + virtual void Add(Field* data, const Value* value) const = 0; + virtual void RemoveLast(Field* data) const = 0; + virtual void SwapElements(Field* data, int index1, int index2) const = 0; + virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator, + Field* other_data) const = 0; + + // Create an iterator that points at the begining of the repeated field. + virtual Iterator* BeginIterator(const Field* data) const = 0; + // Create an iterator that points at the end of the repeated field. + virtual Iterator* EndIterator(const Field* data) const = 0; + // Make a copy of an iterator and return the new copy. + virtual Iterator* CopyIterator(const Field* data, + const Iterator* iterator) const = 0; + // Move an iterator to point to the next element. + virtual Iterator* AdvanceIterator(const Field* data, + Iterator* iterator) const = 0; + // Compare whether two iterators point to the same element. + virtual bool EqualsIterator(const Field* data, const Iterator* a, + const Iterator* b) const = 0; + // Delete an iterator created by BeginIterator(), EndIterator() and + // CopyIterator(). + virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0; + // Like Get() but for iterators. + virtual const Value* GetIteratorValue(const Field* data, + const Iterator* iterator, + Value* scratch_space) const = 0; + + // Templated methods that make using this interface easier for non-message + // types. + template + T Get(const Field* data, int index) const { + typedef typename RefTypeTraits::AccessorValueType ActualType; + ActualType scratch_space; + return static_cast( + *reinterpret_cast( + Get(data, index, static_cast(&scratch_space)))); + } + + template + void Set(Field* data, int index, const ValueType& value) const { + typedef typename RefTypeTraits::AccessorValueType ActualType; + // In this RepeatedFieldAccessor interface we pass/return data using + // raw pointers. Type of the data these raw pointers point to should + // be ActualType. Here we have a ValueType object and want a ActualType + // pointer. We can't cast a ValueType pointer to an ActualType pointer + // directly because their type might be different (for enums ValueType + // may be a generated enum type while ActualType is int32). To be safe + // we make a copy to get a temporary ActualType object and use it. + ActualType tmp = static_cast(value); + Set(data, index, static_cast(&tmp)); + } + + template + void Add(Field* data, const ValueType& value) const { + typedef typename RefTypeTraits::AccessorValueType ActualType; + // In this RepeatedFieldAccessor interface we pass/return data using + // raw pointers. Type of the data these raw pointers point to should + // be ActualType. Here we have a ValueType object and want a ActualType + // pointer. We can't cast a ValueType pointer to an ActualType pointer + // directly because their type might be different (for enums ValueType + // may be a generated enum type while ActualType is int32). To be safe + // we make a copy to get a temporary ActualType object and use it. + ActualType tmp = static_cast(value); + Add(data, static_cast(&tmp)); + } +}; + +// Implement (Mutable)RepeatedFieldRef::iterator +template +class RepeatedFieldRefIterator + : public std::iterator { + typedef typename RefTypeTraits::AccessorValueType AccessorValueType; + typedef typename RefTypeTraits::IteratorValueType IteratorValueType; + typedef typename RefTypeTraits::IteratorPointerType IteratorPointerType; + + public: + // Constructor for non-message fields. + RepeatedFieldRefIterator(const void* data, + const RepeatedFieldAccessor* accessor, + bool begin) + : data_(data), accessor_(accessor), + iterator_(begin ? accessor->BeginIterator(data) : + accessor->EndIterator(data)), + scratch_space_(new AccessorValueType) { + } + // Constructor for message fields. + RepeatedFieldRefIterator(const void* data, + const RepeatedFieldAccessor* accessor, + bool begin, + AccessorValueType* scratch_space) + : data_(data), accessor_(accessor), + iterator_(begin ? accessor->BeginIterator(data) : + accessor->EndIterator(data)), + scratch_space_(scratch_space) { + } + ~RepeatedFieldRefIterator() { + accessor_->DeleteIterator(data_, iterator_); + } + RepeatedFieldRefIterator operator++(int) { + RepeatedFieldRefIterator tmp(*this); + iterator_ = accessor_->AdvanceIterator(data_, iterator_); + return tmp; + } + RepeatedFieldRefIterator& operator++() { + iterator_ = accessor_->AdvanceIterator(data_, iterator_); + return *this; + } + IteratorValueType operator*() const { + return static_cast( + *static_cast( + accessor_->GetIteratorValue( + data_, iterator_, scratch_space_.get()))); + } + IteratorPointerType operator->() const { + return static_cast( + accessor_->GetIteratorValue( + data_, iterator_, scratch_space_.get())); + } + bool operator!=(const RepeatedFieldRefIterator& other) const { + assert(data_ == other.data_); + assert(accessor_ == other.accessor_); + return !accessor_->EqualsIterator(data_, iterator_, other.iterator_); + } + bool operator==(const RepeatedFieldRefIterator& other) const { + return !this->operator!=(other); + } + + RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other) + : data_(other.data_), accessor_(other.accessor_), + iterator_(accessor_->CopyIterator(data_, other.iterator_)) { + } + RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) { + if (this != &other) { + accessor_->DeleteIterator(data_, iterator_); + data_ = other.data_; + accessor_ = other.accessor_; + iterator_ = accessor_->CopyIterator(data_, other.iterator_); + } + return *this; + } + + protected: + const void* data_; + const RepeatedFieldAccessor* accessor_; + void* iterator_; + scoped_ptr scratch_space_; +}; + +// TypeTraits that maps the type parameter T of RepeatedFieldRef or +// MutableRepeatedFieldRef to corresponding iterator type, +// RepeatedFieldAccessor type, etc. +template +struct PrimitiveTraits { + static const bool is_primitive = false; +}; +#define DEFINE_PRIMITIVE(TYPE, type) \ + template<> struct PrimitiveTraits { \ + static const bool is_primitive = true; \ + static const FieldDescriptor::CppType cpp_type = \ + FieldDescriptor::CPPTYPE_ ## TYPE; \ + }; +DEFINE_PRIMITIVE(INT32, int32) +DEFINE_PRIMITIVE(UINT32, uint32) +DEFINE_PRIMITIVE(INT64, int64) +DEFINE_PRIMITIVE(UINT64, uint64) +DEFINE_PRIMITIVE(FLOAT, float) +DEFINE_PRIMITIVE(DOUBLE, double) +DEFINE_PRIMITIVE(BOOL, bool) +#undef DEFINE_PRIMITIVE + +template +struct RefTypeTraits< + T, typename internal::enable_if::is_primitive>::type> { + typedef RepeatedFieldRefIterator iterator; + typedef RepeatedFieldAccessor AccessorType; + typedef T AccessorValueType; + typedef T IteratorValueType; + typedef T* IteratorPointerType; + static const FieldDescriptor::CppType cpp_type = + PrimitiveTraits::cpp_type; + static const Descriptor* GetMessageFieldDescriptor() { + return NULL; + } +}; + +template +struct RefTypeTraits< + T, typename internal::enable_if::value>::type> { + typedef RepeatedFieldRefIterator iterator; + typedef RepeatedFieldAccessor AccessorType; + // We use int32 for repeated enums in RepeatedFieldAccessor. + typedef int32 AccessorValueType; + typedef T IteratorValueType; + typedef int32* IteratorPointerType; + static const FieldDescriptor::CppType cpp_type = + FieldDescriptor::CPPTYPE_ENUM; + static const Descriptor* GetMessageFieldDescriptor() { + return NULL; + } +}; + +template +struct RefTypeTraits< + T, typename internal::enable_if::value>::type> { + typedef RepeatedFieldRefIterator iterator; + typedef RepeatedFieldAccessor AccessorType; + typedef string AccessorValueType; + typedef string IteratorValueType; + typedef string* IteratorPointerType; + static const FieldDescriptor::CppType cpp_type = + FieldDescriptor::CPPTYPE_STRING; + static const Descriptor* GetMessageFieldDescriptor() { + return NULL; + } +}; + +template +struct MessageDescriptorGetter { + static const Descriptor* get() { + return T::default_instance().GetDescriptor(); + } +}; +template<> +struct MessageDescriptorGetter { + static const Descriptor* get() { + return NULL; + } +}; + +template +struct RefTypeTraits< + T, typename internal::enable_if::value>::type> { + typedef RepeatedFieldRefIterator iterator; + typedef RepeatedFieldAccessor AccessorType; + typedef Message AccessorValueType; + typedef const T& IteratorValueType; + typedef const T* IteratorPointerType; + static const FieldDescriptor::CppType cpp_type = + FieldDescriptor::CPPTYPE_MESSAGE; + static const Descriptor* GetMessageFieldDescriptor() { + return MessageDescriptorGetter::get(); + } +}; +} // namespace internal +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc index 62833aab..98c864d3 100644 --- a/src/google/protobuf/repeated_field_reflection_unittest.cc +++ b/src/google/protobuf/repeated_field_reflection_unittest.cc @@ -33,10 +33,12 @@ // Test reflection methods for aggregate access to Repeated[Ptr]Fields. // This test proto2 methods on a proto2 layout. -#include +#include #include +#include #include #include +#include #include namespace google { @@ -58,7 +60,6 @@ static string StrFunc(int i, int j) { return str; } - TEST(RepeatedFieldReflectionTest, RegularFields) { TestAllTypes message; const Reflection* refl = message.GetReflection(); @@ -113,7 +114,7 @@ TEST(RepeatedFieldReflectionTest, RegularFields) { refl->MutableRepeatedPtrField( &message, fd_repeated_foreign_message); - // Make sure we can do get and sets through the Repeated[Ptr]Field objects. + // Make sure we can do gets and sets through the Repeated[Ptr]Field objects. for (int i = 0; i < 10; ++i) { // Check gets through const objects. EXPECT_EQ(rf_int32.Get(i), Func(i, 1)); @@ -158,8 +159,6 @@ TEST(RepeatedFieldReflectionTest, RegularFields) { } - - TEST(RepeatedFieldReflectionTest, ExtensionFields) { TestAllExtensions extended_message; const Reflection* refl = extended_message.GetReflection(); @@ -190,6 +189,515 @@ TEST(RepeatedFieldReflectionTest, ExtensionFields) { } } +template +void TestRepeatedFieldRefIterator( + const Ref& handle, const MessageType& message, + ValueType (MessageType::*GetFunc)(int) const) { + int index = 0; + for (typename Ref::const_iterator it = handle.begin(); + it != handle.end(); ++it) { + ValueType value = static_cast(*it); + EXPECT_EQ((message.*GetFunc)(index), value); + ++index; + } + EXPECT_EQ(handle.size(), index); +} + +TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForRegularFields) { + TestAllTypes message; + const Reflection* refl = message.GetReflection(); + const Descriptor* desc = message.GetDescriptor(); + + for (int i = 0; i < 10; ++i) { + message.add_repeated_int32(Func(i, 1)); + message.add_repeated_double(Func(i, 2)); + message.add_repeated_string(StrFunc(i, 5)); + message.add_repeated_foreign_message()->set_c(Func(i, 6)); + } + + // Get FieldDescriptors for all the fields of interest. + const FieldDescriptor* fd_repeated_int32 = + desc->FindFieldByName("repeated_int32"); + const FieldDescriptor* fd_repeated_double = + desc->FindFieldByName("repeated_double"); + const FieldDescriptor* fd_repeated_string = + desc->FindFieldByName("repeated_string"); + const FieldDescriptor* fd_repeated_foreign_message = + desc->FindFieldByName("repeated_foreign_message"); + + // Get RepeatedFieldRef objects for all fields of interest. + const RepeatedFieldRef rf_int32 = + refl->GetRepeatedFieldRef(message, fd_repeated_int32); + const RepeatedFieldRef rf_double = + refl->GetRepeatedFieldRef(message, fd_repeated_double); + const RepeatedFieldRef rf_string = + refl->GetRepeatedFieldRef(message, fd_repeated_string); + const RepeatedFieldRef rf_foreign_message = + refl->GetRepeatedFieldRef( + message, fd_repeated_foreign_message); + const RepeatedFieldRef rf_message = + refl->GetRepeatedFieldRef( + message, fd_repeated_foreign_message); + + // Get MutableRepeatedFieldRef objects for all fields of interest. + const MutableRepeatedFieldRef mrf_int32 = + refl->GetMutableRepeatedFieldRef(&message, fd_repeated_int32); + const MutableRepeatedFieldRef mrf_double = + refl->GetMutableRepeatedFieldRef(&message, fd_repeated_double); + const MutableRepeatedFieldRef mrf_string = + refl->GetMutableRepeatedFieldRef(&message, fd_repeated_string); + const MutableRepeatedFieldRef mrf_foreign_message = + refl->GetMutableRepeatedFieldRef( + &message, fd_repeated_foreign_message); + const MutableRepeatedFieldRef mrf_message = + refl->GetMutableRepeatedFieldRef( + &message, fd_repeated_foreign_message); + + EXPECT_EQ(message.repeated_int32_size(), rf_int32.size()); + EXPECT_EQ(message.repeated_int32_size(), mrf_int32.size()); + EXPECT_EQ(message.repeated_double_size(), rf_double.size()); + EXPECT_EQ(message.repeated_double_size(), mrf_double.size()); + EXPECT_EQ(message.repeated_string_size(), rf_string.size()); + EXPECT_EQ(message.repeated_string_size(), mrf_string.size()); + EXPECT_EQ(message.repeated_foreign_message_size(), + rf_foreign_message.size()); + EXPECT_EQ(message.repeated_foreign_message_size(), + mrf_foreign_message.size()); + EXPECT_EQ(message.repeated_foreign_message_size(), rf_message.size()); + EXPECT_EQ(message.repeated_foreign_message_size(), mrf_message.size()); + + EXPECT_FALSE(rf_int32.empty()); + EXPECT_FALSE(mrf_int32.empty()); + EXPECT_FALSE(rf_double.empty()); + EXPECT_FALSE(mrf_double.empty()); + EXPECT_FALSE(rf_string.empty()); + EXPECT_FALSE(mrf_string.empty()); + EXPECT_FALSE(rf_foreign_message.empty()); + EXPECT_FALSE(mrf_foreign_message.empty()); + EXPECT_FALSE(rf_message.empty()); + EXPECT_FALSE(mrf_message.empty()); + + // Make sure we can do gets and sets through the RepeatedFieldRef objects. + for (int i = 0; i < 10; ++i) { + // Check gets through const objects. + EXPECT_EQ(rf_int32.Get(i), Func(i, 1)); + EXPECT_EQ(rf_double.Get(i), Func(i, 2)); + EXPECT_EQ(rf_string.Get(i), StrFunc(i, 5)); + ForeignMessage scratch_space; + EXPECT_EQ(rf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6)); + EXPECT_EQ(down_cast( + rf_message.Get(i, &scratch_space)).c(), Func(i, 6)); + + // Check gets through mutable objects. + EXPECT_EQ(mrf_int32.Get(i), Func(i, 1)); + EXPECT_EQ(mrf_double.Get(i), Func(i, 2)); + EXPECT_EQ(mrf_string.Get(i), StrFunc(i, 5)); + EXPECT_EQ(mrf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6)); + EXPECT_EQ(down_cast( + mrf_message.Get(i, &scratch_space)).c(), Func(i, 6)); + + // Check sets through mutable objects. + mrf_int32.Set(i, Func(i, -1)); + mrf_double.Set(i, Func(i, -2)); + mrf_string.Set(i, StrFunc(i, -5)); + ForeignMessage foreign_message; + foreign_message.set_c(Func(i, -6)); + mrf_foreign_message.Set(i, foreign_message); + EXPECT_EQ(message.repeated_int32(i), Func(i, -1)); + EXPECT_EQ(message.repeated_double(i), Func(i, -2)); + EXPECT_EQ(message.repeated_string(i), StrFunc(i, -5)); + EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, -6)); + foreign_message.set_c(Func(i, 7)); + mrf_message.Set(i, foreign_message); + EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7)); + } + + // Test iterators. + TestRepeatedFieldRefIterator(rf_int32, message, + &TestAllTypes::repeated_int32); + TestRepeatedFieldRefIterator(rf_double, message, + &TestAllTypes::repeated_double); + TestRepeatedFieldRefIterator(rf_string, message, + &TestAllTypes::repeated_string); + + // Test iterators for message fields. + typedef RepeatedFieldRef::iterator MessageIterator; + int index = 0; + for (MessageIterator it = rf_foreign_message.begin(); + it != rf_foreign_message.end(); ++it) { + EXPECT_EQ(message.repeated_foreign_message(index).c(), it->c()); + ++index; + } + EXPECT_EQ(10, index); + + // Test iterator operators that are not ususally used in regular for-loops. + // Including: post increment, assign, ==. + MessageIterator old_it = rf_foreign_message.begin(); + MessageIterator new_it = old_it++; + EXPECT_FALSE(old_it == new_it); + // Check that old_it++ increments old_it once. + for (index = 1; old_it != rf_foreign_message.end(); ++old_it, ++index) { + EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c()); + } + EXPECT_EQ(10, index); + // Test assign operator. + old_it = new_it; + for (index = 0; old_it != rf_foreign_message.end(); ++old_it, ++index) { + EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c()); + } + EXPECT_EQ(10, index); + // Check that the returned value of old_it++ is the one before increment. + for (index = 0; new_it != rf_foreign_message.end(); ++new_it, ++index) { + EXPECT_EQ(message.repeated_foreign_message(index).c(), new_it->c()); + } + EXPECT_EQ(10, index); + + // Test MutableRepeatedFieldRef::Add() + mrf_int32.Add(1234); + mrf_double.Add(1234.0); + mrf_string.Add("1234"); + ForeignMessage foreign_message; + foreign_message.set_c(1234); + mrf_foreign_message.Add(foreign_message); + EXPECT_EQ(1234, message.repeated_int32(10)); + EXPECT_EQ(1234.0, message.repeated_double(10)); + EXPECT_EQ("1234", message.repeated_string(10)); + EXPECT_EQ(1234, message.repeated_foreign_message(10).c()); + + // Test MutableRepeatedFieldRef::RemoveLast() + mrf_int32.RemoveLast(); + mrf_double.RemoveLast(); + mrf_string.RemoveLast(); + mrf_foreign_message.RemoveLast(); + EXPECT_EQ(10, message.repeated_int32_size()); + EXPECT_EQ(10, message.repeated_double_size()); + EXPECT_EQ(10, message.repeated_string_size()); + EXPECT_EQ(10, message.repeated_foreign_message_size()); + + // Test MutableRepeatedFieldRef::SwapElements() + mrf_int32.SwapElements(0, 9); + mrf_double.SwapElements(0, 9); + mrf_string.SwapElements(0, 9); + mrf_foreign_message.SwapElements(0, 9); + EXPECT_EQ(Func(9, -1), message.repeated_int32(0)); + EXPECT_EQ(Func(0, -1), message.repeated_int32(9)); + EXPECT_EQ(Func(9, -2), message.repeated_double(0)); + EXPECT_EQ(Func(0, -2), message.repeated_double(9)); + EXPECT_EQ(StrFunc(9, -5), message.repeated_string(0)); + EXPECT_EQ(StrFunc(0, -5), message.repeated_string(9)); + EXPECT_EQ(Func(9, 7), message.repeated_foreign_message(0).c()); + EXPECT_EQ(Func(0, 7), message.repeated_foreign_message(9).c()); + + // Test MutableRepeatedFieldRef::Clear() + mrf_int32.Clear(); + mrf_double.Clear(); + mrf_string.Clear(); + mrf_foreign_message.Clear(); + EXPECT_EQ(0, message.repeated_int32_size()); + EXPECT_EQ(0, message.repeated_double_size()); + EXPECT_EQ(0, message.repeated_string_size()); + EXPECT_EQ(0, message.repeated_foreign_message_size()); + + // Test (Mutable)RepeatedFieldRef::empty() + EXPECT_TRUE(rf_int32.empty()); + EXPECT_TRUE(mrf_int32.empty()); + EXPECT_TRUE(rf_double.empty()); + EXPECT_TRUE(mrf_double.empty()); + EXPECT_TRUE(rf_string.empty()); + EXPECT_TRUE(mrf_string.empty()); + EXPECT_TRUE(rf_foreign_message.empty()); + EXPECT_TRUE(mrf_foreign_message.empty()); + EXPECT_TRUE(rf_message.empty()); + EXPECT_TRUE(mrf_message.empty()); + + // Make sure types are checked correctly at runtime. + const FieldDescriptor* fd_optional_int32 = + desc->FindFieldByName("optional_int32"); + EXPECT_DEATH(refl->GetRepeatedFieldRef( + message, fd_optional_int32), ""); + EXPECT_DEATH(refl->GetRepeatedFieldRef( + message, fd_repeated_int32), ""); + EXPECT_DEATH(refl->GetRepeatedFieldRef( + message, fd_repeated_foreign_message), ""); +} + +TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForEnums) { + TestAllTypes message; + const Reflection* refl = message.GetReflection(); + const Descriptor* desc = message.GetDescriptor(); + + for (int i = 0; i < 10; ++i) { + message.add_repeated_nested_enum(TestAllTypes::BAR); + } + + const FieldDescriptor* fd_repeated_nested_enum = + desc->FindFieldByName("repeated_nested_enum"); + const RepeatedFieldRef enum_ref = + refl->GetRepeatedFieldRef( + message, fd_repeated_nested_enum); + const MutableRepeatedFieldRef + mutable_enum_ref = + refl->GetMutableRepeatedFieldRef( + &message, fd_repeated_nested_enum); + const RepeatedFieldRef int32_ref = + refl->GetRepeatedFieldRef( + message, fd_repeated_nested_enum); + const MutableRepeatedFieldRef mutable_int32_ref = + refl->GetMutableRepeatedFieldRef( + &message, fd_repeated_nested_enum); + + EXPECT_EQ(message.repeated_nested_enum_size(), enum_ref.size()); + EXPECT_EQ(message.repeated_nested_enum_size(), mutable_enum_ref.size()); + EXPECT_EQ(message.repeated_nested_enum_size(), int32_ref.size()); + EXPECT_EQ(message.repeated_nested_enum_size(), mutable_int32_ref.size()); + + EXPECT_FALSE(enum_ref.empty()); + EXPECT_FALSE(mutable_enum_ref.empty()); + EXPECT_FALSE(int32_ref.empty()); + EXPECT_FALSE(mutable_int32_ref.empty()); + + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(i)); + EXPECT_EQ(TestAllTypes::BAR, mutable_enum_ref.Get(i)); + mutable_enum_ref.Set(i, TestAllTypes::BAZ); + EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(i)); + EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i)); + + message.set_repeated_nested_enum(i, TestAllTypes::BAR); + EXPECT_EQ(TestAllTypes::BAR, int32_ref.Get(i)); + EXPECT_EQ(TestAllTypes::BAR, mutable_int32_ref.Get(i)); + mutable_int32_ref.Set(i, TestAllTypes::BAZ); + EXPECT_EQ(TestAllTypes::BAZ, int32_ref.Get(i)); + EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i)); + } + + TestRepeatedFieldRefIterator(enum_ref, message, + &TestAllTypes::repeated_nested_enum); + TestRepeatedFieldRefIterator(int32_ref, message, + &TestAllTypes::repeated_nested_enum); + + // Test Add() + mutable_enum_ref.Add(TestAllTypes::FOO); + EXPECT_EQ(TestAllTypes::FOO, message.repeated_nested_enum(10)); + mutable_int32_ref.Add(TestAllTypes::BAR); + EXPECT_EQ(TestAllTypes::BAR, message.repeated_nested_enum(11)); + + // Test RemoveLast() + mutable_enum_ref.RemoveLast(); + EXPECT_EQ(11, message.repeated_nested_enum_size()); + mutable_int32_ref.RemoveLast(); + EXPECT_EQ(10, message.repeated_nested_enum_size()); + + // Test SwapElements() + mutable_enum_ref.Set(0, TestAllTypes::BAR); + mutable_enum_ref.Set(9, TestAllTypes::BAZ); + mutable_enum_ref.SwapElements(0, 9); + EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(0)); + EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(9)); + mutable_int32_ref.SwapElements(0, 9); + EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(0)); + EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(9)); + + // Test Clear() + mutable_enum_ref.Clear(); + EXPECT_EQ(0, message.repeated_nested_enum_size()); + mutable_enum_ref.Add(TestAllTypes::FOO); + EXPECT_EQ(1, message.repeated_nested_enum_size()); + mutable_int32_ref.Clear(); + EXPECT_EQ(0, message.repeated_nested_enum_size()); + + // Test empty() + EXPECT_TRUE(enum_ref.empty()); + EXPECT_TRUE(mutable_enum_ref.empty()); + EXPECT_TRUE(int32_ref.empty()); + EXPECT_TRUE(mutable_int32_ref.empty()); +} + +TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForExtensionFields) { + TestAllExtensions extended_message; + const Reflection* refl = extended_message.GetReflection(); + const Descriptor* desc = extended_message.GetDescriptor(); + + for (int i = 0; i < 10; ++i) { + extended_message.AddExtension( + unittest::repeated_int64_extension, Func(i, 1)); + } + + const FieldDescriptor* fd_repeated_int64_extension = + desc->file()->FindExtensionByName("repeated_int64_extension"); + GOOGLE_CHECK(fd_repeated_int64_extension != NULL); + + const RepeatedFieldRef rf_int64_extension = + refl->GetRepeatedFieldRef(extended_message, + fd_repeated_int64_extension); + + const MutableRepeatedFieldRef mrf_int64_extension = + refl->GetMutableRepeatedFieldRef(&extended_message, + fd_repeated_int64_extension); + + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i)); + mrf_int64_extension.Set(i, Func(i, -1)); + EXPECT_EQ(Func(i, -1), + extended_message.GetExtension(unittest::repeated_int64_extension, i)); + } +} + + +TEST(RepeatedFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) { + // Set-up message content. + TestAllTypes m0, m1, m2; + for (int i = 0; i < 10; ++i) { + m0.add_repeated_int32(Func(i, 1)); + m0.add_repeated_double(Func(i, 2)); + m0.add_repeated_string(StrFunc(i, 5)); + m0.add_repeated_foreign_message()->set_c(Func(i, 6)); + m0.add_repeated_nested_enum(TestAllTypes::FOO); + m1.add_repeated_int32(Func(i, 11)); + m1.add_repeated_double(Func(i, 12)); + m1.add_repeated_string(StrFunc(i, 15)); + m1.add_repeated_foreign_message()->set_c(Func(i, 16)); + m1.add_repeated_nested_enum(TestAllTypes::BAR); + m2.add_repeated_int32(Func(i, 21)); + m2.add_repeated_double(Func(i, 22)); + m2.add_repeated_string(StrFunc(i, 25)); + m2.add_repeated_foreign_message()->set_c(Func(i, 26)); + m2.add_repeated_nested_enum(TestAllTypes::BAZ); + } + + const Reflection* refl = m0.GetReflection(); + const Descriptor* desc = m0.GetDescriptor(); + + // Get FieldDescriptors for all the fields of interest. + const FieldDescriptor* fd_repeated_int32 = + desc->FindFieldByName("repeated_int32"); + const FieldDescriptor* fd_repeated_double = + desc->FindFieldByName("repeated_double"); + const FieldDescriptor* fd_repeated_string = + desc->FindFieldByName("repeated_string"); + const FieldDescriptor* fd_repeated_foreign_message = + desc->FindFieldByName("repeated_foreign_message"); + const FieldDescriptor* fd_repeated_nested_enum = + desc->FindFieldByName("repeated_nested_enum"); + + // Get MutableRepeatedFieldRef objects for all fields of interest. + const MutableRepeatedFieldRef mrf_int32 = + refl->GetMutableRepeatedFieldRef(&m0, fd_repeated_int32); + const MutableRepeatedFieldRef mrf_double = + refl->GetMutableRepeatedFieldRef(&m0, fd_repeated_double); + const MutableRepeatedFieldRef mrf_string = + refl->GetMutableRepeatedFieldRef(&m0, fd_repeated_string); + const MutableRepeatedFieldRef mrf_foreign_message = + refl->GetMutableRepeatedFieldRef( + &m0, fd_repeated_foreign_message); + const MutableRepeatedFieldRef + mrf_nested_enum = + refl->GetMutableRepeatedFieldRef( + &m0, fd_repeated_nested_enum); + + // Test MutableRepeatedRef::CopyFrom + mrf_int32.CopyFrom( + refl->GetRepeatedFieldRef(m1, fd_repeated_int32)); + mrf_double.CopyFrom( + refl->GetRepeatedFieldRef(m1, fd_repeated_double)); + mrf_string.CopyFrom( + refl->GetRepeatedFieldRef(m1, fd_repeated_string)); + mrf_foreign_message.CopyFrom( + refl->GetRepeatedFieldRef( + m1, fd_repeated_foreign_message)); + mrf_nested_enum.CopyFrom( + refl->GetRepeatedFieldRef( + m1, fd_repeated_nested_enum)); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(Func(i, 11), m0.repeated_int32(i)); + EXPECT_EQ(Func(i, 12), m0.repeated_double(i)); + EXPECT_EQ(StrFunc(i, 15), m0.repeated_string(i)); + EXPECT_EQ(Func(i, 16), m0.repeated_foreign_message(i).c()); + EXPECT_EQ(TestAllTypes::BAR, m0.repeated_nested_enum(i)); + } + + // Test MutableRepeatedRef::MergeFrom + mrf_int32.MergeFrom( + refl->GetRepeatedFieldRef(m2, fd_repeated_int32)); + mrf_double.MergeFrom( + refl->GetRepeatedFieldRef(m2, fd_repeated_double)); + mrf_string.MergeFrom( + refl->GetRepeatedFieldRef(m2, fd_repeated_string)); + mrf_foreign_message.MergeFrom( + refl->GetRepeatedFieldRef( + m2, fd_repeated_foreign_message)); + mrf_nested_enum.MergeFrom( + refl->GetRepeatedFieldRef( + m2, fd_repeated_nested_enum)); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(Func(i, 21), m0.repeated_int32(i + 10)); + EXPECT_EQ(Func(i, 22), m0.repeated_double(i + 10)); + EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i + 10)); + EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i + 10).c()); + EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i + 10)); + } + + // Test MutableRepeatedRef::Swap + // Swap between m0 and m2. + mrf_int32.Swap( + refl->GetMutableRepeatedFieldRef(&m2, fd_repeated_int32)); + mrf_double.Swap( + refl->GetMutableRepeatedFieldRef(&m2, fd_repeated_double)); + mrf_string.Swap( + refl->GetMutableRepeatedFieldRef(&m2, fd_repeated_string)); + mrf_foreign_message.Swap( + refl->GetMutableRepeatedFieldRef( + &m2, fd_repeated_foreign_message)); + mrf_nested_enum.Swap( + refl->GetMutableRepeatedFieldRef( + &m2, fd_repeated_nested_enum)); + for (int i = 0; i < 10; ++i) { + // Check the content of m0. + EXPECT_EQ(Func(i, 21), m0.repeated_int32(i)); + EXPECT_EQ(Func(i, 22), m0.repeated_double(i)); + EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i)); + EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i).c()); + EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i)); + + // Check the content of m2. + EXPECT_EQ(Func(i, 11), m2.repeated_int32(i)); + EXPECT_EQ(Func(i, 12), m2.repeated_double(i)); + EXPECT_EQ(StrFunc(i, 15), m2.repeated_string(i)); + EXPECT_EQ(Func(i, 16), m2.repeated_foreign_message(i).c()); + EXPECT_EQ(TestAllTypes::BAR, m2.repeated_nested_enum(i)); + EXPECT_EQ(Func(i, 21), m2.repeated_int32(i + 10)); + EXPECT_EQ(Func(i, 22), m2.repeated_double(i + 10)); + EXPECT_EQ(StrFunc(i, 25), m2.repeated_string(i + 10)); + EXPECT_EQ(Func(i, 26), m2.repeated_foreign_message(i + 10).c()); + EXPECT_EQ(TestAllTypes::BAZ, m2.repeated_nested_enum(i + 10)); + } +} + +// Test that GetRepeatedFieldRef/MutableRepeatedFieldRef works with +// DynamicMessage. +TEST(RepeatedFieldReflectionTest, RepeatedFieldRefDynamicMessage) { + // DynamicMessage shares the same memory layout as generated message + // and use the same GeneratedMessageReflection code for reflection. + // All code paths should already be covered by the other tests for + // generated messages. Here we just test one field. + + const Descriptor* desc = TestAllTypes::descriptor(); + const FieldDescriptor* fd_repeated_int32 = + desc->FindFieldByName("repeated_int32"); + + DynamicMessageFactory factory; + scoped_ptr dynamic_message(factory.GetPrototype(desc)->New()); + const Reflection* refl = dynamic_message->GetReflection(); + + MutableRepeatedFieldRef rf_int32 = + refl->GetMutableRepeatedFieldRef( + dynamic_message.get(), fd_repeated_int32); + rf_int32.Add(1234); + EXPECT_EQ(1, refl->FieldSize(*dynamic_message, fd_repeated_int32)); + EXPECT_EQ(1234, refl->GetRepeatedInt32(*dynamic_message, + fd_repeated_int32, 0)); +} + } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index f4d48f59..9942af50 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -92,7 +92,8 @@ TEST(RepeatedField, Small) { EXPECT_TRUE(field.empty()); EXPECT_EQ(field.size(), 0); - int expected_usage = 4 * sizeof(int); + // Additional 8 bytes are for 'struct Rep' header. + int expected_usage = 4 * sizeof(int) + 8; EXPECT_EQ(field.SpaceUsedExcludingSelf(), expected_usage); } @@ -295,6 +296,39 @@ TEST(RepeatedField, CopyFromSelf) { EXPECT_EQ(3, me.Get(0)); } +TEST(RepeatedField, Erase) { + RepeatedField me; + RepeatedField::iterator it = me.erase(me.begin(), me.end()); + EXPECT_TRUE(me.begin() == it); + EXPECT_EQ(0, me.size()); + + me.Add(1); + me.Add(2); + me.Add(3); + it = me.erase(me.begin(), me.end()); + EXPECT_TRUE(me.begin() == it); + EXPECT_EQ(0, me.size()); + + me.Add(4); + me.Add(5); + me.Add(6); + it = me.erase(me.begin() + 2, me.end()); + EXPECT_TRUE(me.begin() + 2 == it); + EXPECT_EQ(2, me.size()); + EXPECT_EQ(4, me.Get(0)); + EXPECT_EQ(5, me.Get(1)); + + me.Add(6); + me.Add(7); + me.Add(8); + it = me.erase(me.begin() + 1, me.begin() + 3); + EXPECT_TRUE(me.begin() + 1 == it); + EXPECT_EQ(3, me.size()); + EXPECT_EQ(4, me.Get(0)); + EXPECT_EQ(7, me.Get(1)); + EXPECT_EQ(8, me.Get(2)); +} + TEST(RepeatedField, CopyConstruct) { RepeatedField source; source.Add(1); @@ -741,6 +775,39 @@ TEST(RepeatedPtrField, CopyFromSelf) { EXPECT_EQ("1", me.Get(0)); } +TEST(RepeatedPtrField, Erase) { + RepeatedPtrField me; + RepeatedPtrField::iterator it = me.erase(me.begin(), me.end()); + EXPECT_TRUE(me.begin() == it); + EXPECT_EQ(0, me.size()); + + *me.Add() = "1"; + *me.Add() = "2"; + *me.Add() = "3"; + it = me.erase(me.begin(), me.end()); + EXPECT_TRUE(me.begin() == it); + EXPECT_EQ(0, me.size()); + + *me.Add() = "4"; + *me.Add() = "5"; + *me.Add() = "6"; + it = me.erase(me.begin() + 2, me.end()); + EXPECT_TRUE(me.begin() + 2 == it); + EXPECT_EQ(2, me.size()); + EXPECT_EQ("4", me.Get(0)); + EXPECT_EQ("5", me.Get(1)); + + *me.Add() = "6"; + *me.Add() = "7"; + *me.Add() = "8"; + it = me.erase(me.begin() + 1, me.begin() + 3); + EXPECT_TRUE(me.begin() + 1 == it); + EXPECT_EQ(3, me.size()); + EXPECT_EQ("4", me.Get(0)); + EXPECT_EQ("7", me.Get(1)); + EXPECT_EQ("8", me.Get(2)); +} + TEST(RepeatedPtrField, CopyConstruct) { RepeatedPtrField source; source.Add()->assign("1"); diff --git a/src/google/protobuf/stubs/atomic_sequence_num.h b/src/google/protobuf/stubs/atomic_sequence_num.h new file mode 100644 index 00000000..bb20942f --- /dev/null +++ b/src/google/protobuf/stubs/atomic_sequence_num.h @@ -0,0 +1,54 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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_ATOMIC_SEQUENCE_NUM_H_ +#define GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_ + +#include + +namespace google { +namespace protobuf { +namespace internal { + +class SequenceNumber { + public: + SequenceNumber() : word_(0) {} + + AtomicWord GetNext() { + return NoBarrier_AtomicIncrement(&word_, 1) - 1; + } + private: + AtomicWord word_; +}; + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_ diff --git a/src/google/protobuf/stubs/casts.h b/src/google/protobuf/stubs/casts.h new file mode 100644 index 00000000..cccf65a1 --- /dev/null +++ b/src/google/protobuf/stubs/casts.h @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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_CASTS_H__ +#define GOOGLE_PROTOBUF_CASTS_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace internal { +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) { + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +template // use like this: down_cast(foo); +inline To down_cast(From& f) { + typedef typename remove_reference::type* ToAsPointer; + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + // RTTI: debug mode only! + assert(dynamic_cast(&f) != NULL); +#endif + return *static_cast(&f); +} + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::implicit_cast; +using internal::down_cast; + +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_CASTS_H__ diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index 1e02b228..54e00ccb 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -171,6 +171,7 @@ DECLARE_STREAM_OPERATOR(uint , "%u" ) DECLARE_STREAM_OPERATOR(long , "%ld") DECLARE_STREAM_OPERATOR(unsigned long, "%lu") DECLARE_STREAM_OPERATOR(double , "%g" ) +DECLARE_STREAM_OPERATOR(void* , "%p" ) #undef DECLARE_STREAM_OPERATOR LogMessage::LogMessage(LogLevel level, const char* filename, int line) diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index dde48f47..ca7be71f 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -218,6 +218,17 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); #endif #endif +#ifndef GOOGLE_ATTRIBUTE_NOINLINE +#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +// For functions we want to force not inline. +// Introduced in gcc 3.1. +#define GOOGLE_ATTRIBUTE_NOINLINE __attribute__ ((noinline)) +#else +// Other compilers will have to figure it out for themselves. +#define GOOGLE_ATTRIBUTE_NOINLINE +#endif +#endif + #ifndef GOOGLE_ATTRIBUTE_DEPRECATED #ifdef __GNUC__ // If the method/variable/type is used anywhere, produce a warning. @@ -236,6 +247,15 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); #endif #endif +#ifndef GOOGLE_PREDICT_FALSE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_FALSE +#endif +#endif + // Delimits a block of code which may write to memory which is simultaneously // written by other threads, but which has been determined to be thread-safe // (e.g. because it is an idempotent write). @@ -246,6 +266,52 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); #define GOOGLE_SAFE_CONCURRENT_WRITES_END() #endif +#define GOOGLE_GUARDED_BY(x) + +// x86 and x86-64 can perform unaligned loads/stores directly. +#if defined(_M_X64) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(__i386__) + +#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) +#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) +#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast(_p)) + +#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast(_p) = (_val)) + +#else +inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) { + uint16 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) { + uint32 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) { + uint64 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) { + memcpy(p, &v, sizeof v); +} + +inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) { + memcpy(p, &v, sizeof v); +} + +inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) { + memcpy(p, &v, sizeof v); +} +#endif + // =================================================================== // from google3/base/basictypes.h @@ -288,71 +354,6 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); ((sizeof(a) / sizeof(*(a))) / \ static_cast(!(sizeof(a) % sizeof(*(a))))) -namespace internal { - -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertable to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: -// -// implicit_cast(expr) -// -// implicit_cast would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -template -inline To implicit_cast(From const &f) { - return f; -} - -// When you upcast (that is, cast a pointer from type Foo to type -// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts -// always succeed. When you downcast (that is, cast a pointer from -// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because -// how do you know the pointer is really of type SubclassOfFoo? It -// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, -// when you downcast, you should use this macro. In debug mode, we -// use dynamic_cast<> to double-check the downcast is legal (we die -// if it's not). In normal mode, we do the efficient static_cast<> -// instead. Thus, it's important to test in debug mode to make sure -// the cast is legal! -// This is the only place in the code we should use dynamic_cast<>. -// In particular, you SHOULDN'T be using dynamic_cast<> in order to -// do RTTI (eg code like this: -// if (dynamic_cast(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. - -template // use like this: down_cast(foo); -inline To down_cast(From* f) { // so we only accept pointers - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. - if (false) { - implicit_cast(0); - } - -#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) - assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! -#endif - return static_cast(f); -} - -} // namespace internal - -// We made these internal so that they would show up as such in the docs, -// but we don't want to stick "internal::" in front of them everywhere. -using internal::implicit_cast; -using internal::down_cast; - // The COMPILE_ASSERT macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: @@ -657,6 +658,7 @@ class LIBPROTOBUF_EXPORT LogMessage { LogMessage& operator<<(long value); LogMessage& operator<<(unsigned long value); LogMessage& operator<<(double value); + LogMessage& operator<<(void* value); private: friend class LogFinisher; @@ -731,7 +733,8 @@ T* CheckNotNull(const char* /* file */, int /* line */, } } // namespace internal #define GOOGLE_CHECK_NOTNULL(A) \ - internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A)) + ::google::protobuf::internal::CheckNotNull(\ + __FILE__, __LINE__, "'" #A "' must not be NULL", (A)) #ifdef NDEBUG diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc index cb892072..7eb4e317 100644 --- a/src/google/protobuf/stubs/common_unittest.cc +++ b/src/google/protobuf/stubs/common_unittest.cc @@ -31,6 +31,7 @@ // Author: kenton@google.com (Kenton Varda) #include +#include #include #include #include diff --git a/src/google/protobuf/stubs/fastmem.h b/src/google/protobuf/stubs/fastmem.h new file mode 100644 index 00000000..e553f142 --- /dev/null +++ b/src/google/protobuf/stubs/fastmem.h @@ -0,0 +1,153 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + +// Fast memory copying and comparison routines. +// strings::fastmemcmp_inlined() replaces memcmp() +// strings::memcpy_inlined() replaces memcpy() +// strings::memeq(a, b, n) replaces memcmp(a, b, n) == 0 +// +// strings::*_inlined() routines are inline versions of the +// routines exported by this module. Sometimes using the inlined +// versions is faster. Measure before using the inlined versions. +// +// Performance measurement: +// strings::fastmemcmp_inlined +// Analysis: memcmp, fastmemcmp_inlined, fastmemcmp +// 2012-01-30 + +#ifndef GOOGLE_PROTOBUF_STUBS_FASTMEM_H_ +#define GOOGLE_PROTOBUF_STUBS_FASTMEM_H_ + +#include +#include +#include +#include + +#include + +namespace google { +namespace protobuf { +namespace internal { + +// Return true if the n bytes at a equal the n bytes at b. +// The regions are allowed to overlap. +// +// The performance is similar to the performance memcmp(), but faster for +// moderately-sized inputs, or inputs that share a common prefix and differ +// somewhere in their last 8 bytes. Further optimizations can be added later +// if it makes sense to do so.:w +inline bool memeq(const char* a, const char* b, size_t n) { + size_t n_rounded_down = n & ~static_cast(7); + if (GOOGLE_PREDICT_FALSE(n_rounded_down == 0)) { // n <= 7 + return memcmp(a, b, n) == 0; + } + // n >= 8 + uint64 u = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b); + uint64 v = GOOGLE_UNALIGNED_LOAD64(a + n - 8) ^ GOOGLE_UNALIGNED_LOAD64(b + n - 8); + if ((u | v) != 0) { // The first or last 8 bytes differ. + return false; + } + a += 8; + b += 8; + n = n_rounded_down - 8; + if (n > 128) { + // As of 2012, memcmp on x86-64 uses a big unrolled loop with SSE2 + // instructions, and while we could try to do something faster, it + // doesn't seem worth pursuing. + return memcmp(a, b, n) == 0; + } + for (; n >= 16; n -= 16) { + uint64 x = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b); + uint64 y = GOOGLE_UNALIGNED_LOAD64(a + 8) ^ GOOGLE_UNALIGNED_LOAD64(b + 8); + if ((x | y) != 0) { + return false; + } + a += 16; + b += 16; + } + // n must be 0 or 8 now because it was a multiple of 8 at the top of the loop. + return n == 0 || GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b); +} + +inline int fastmemcmp_inlined(const char *a, const char *b, size_t n) { + if (n >= 64) { + return memcmp(a, b, n); + } + const char* a_limit = a + n; + while (a + sizeof(uint64) <= a_limit && + GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b)) { + a += sizeof(uint64); + b += sizeof(uint64); + } + if (a + sizeof(uint32) <= a_limit && + GOOGLE_UNALIGNED_LOAD32(a) == GOOGLE_UNALIGNED_LOAD32(b)) { + a += sizeof(uint32); + b += sizeof(uint32); + } + while (a < a_limit) { + int d = static_cast(*a++) - static_cast(*b++); + if (d) return d; + } + return 0; +} + +// The standard memcpy operation is slow for variable small sizes. +// This implementation inlines the optimal realization for sizes 1 to 16. +// To avoid code bloat don't use it in case of not performance-critical spots, +// nor when you don't expect very frequent values of size <= 16. +inline void memcpy_inlined(char *dst, const char *src, size_t size) { + // Compiler inlines code with minimal amount of data movement when third + // parameter of memcpy is a constant. + switch (size) { + case 1: memcpy(dst, src, 1); break; + case 2: memcpy(dst, src, 2); break; + case 3: memcpy(dst, src, 3); break; + case 4: memcpy(dst, src, 4); break; + case 5: memcpy(dst, src, 5); break; + case 6: memcpy(dst, src, 6); break; + case 7: memcpy(dst, src, 7); break; + case 8: memcpy(dst, src, 8); break; + case 9: memcpy(dst, src, 9); break; + case 10: memcpy(dst, src, 10); break; + case 11: memcpy(dst, src, 11); break; + case 12: memcpy(dst, src, 12); break; + case 13: memcpy(dst, src, 13); break; + case 14: memcpy(dst, src, 14); break; + case 15: memcpy(dst, src, 15); break; + case 16: memcpy(dst, src, 16); break; + default: memcpy(dst, src, size); break; + } +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_FASTMEM_H_ diff --git a/src/google/protobuf/stubs/singleton.h b/src/google/protobuf/stubs/singleton.h new file mode 100644 index 00000000..e123e4fe --- /dev/null +++ b/src/google/protobuf/stubs/singleton.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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_STUBS_SINGLETON_H__ +#define GOOGLE_PROTOBUF_STUBS_SINGLETON_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { +template +class Singleton { + public: + static T* get() { + GoogleOnceInit(&once_, &Singleton::Init); + return instance_; + } + private: + static void Init() { + instance_ = new T(); + } + static ProtobufOnceType once_; + static T* instance_; +}; + +template +ProtobufOnceType Singleton::once_; + +template +T* Singleton::instance_; +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_SINGLETON_H__ diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index a8982593..86d45685 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -94,6 +94,34 @@ void StripString(string* s, const char* remove, char replacewith) { } } +void StripWhitespace(string* str) { + int str_length = str->length(); + + // Strip off leading whitespace. + int first = 0; + while (first < str_length && ascii_isspace(str->at(first))) { + ++first; + } + // If entire string is white space. + if (first == str_length) { + str->clear(); + return; + } + if (first > 0) { + str->erase(0, first); + str_length -= first; + } + + // Strip off trailing whitespace. + int last = str_length - 1; + while (last >= 0 && ascii_isspace(str->at(last))) { + --last; + } + if (last != (str_length - 1) && last >= 0) { + str->erase(last + 1, string::npos); + } +} + // ---------------------------------------------------------------------- // StringReplace() // Replace the "old" pattern with the "new" pattern in a string, @@ -1275,5 +1303,33 @@ string ToHex(uint64 num) { return string(bufptr, buf + 16 - bufptr); } +int GlobalReplaceSubstring(const string& substring, + const string& replacement, + string* s) { + GOOGLE_CHECK(s != NULL); + if (s->empty() || substring.empty()) + return 0; + string tmp; + int num_replacements = 0; + int pos = 0; + for (int match_pos = s->find(substring.data(), pos, substring.length()); + match_pos != string::npos; + pos = match_pos + substring.length(), + match_pos = s->find(substring.data(), pos, substring.length())) { + ++num_replacements; + // Append the original content before the match. + tmp.append(*s, pos, match_pos - pos); + // Append the replacement for the match. + tmp.append(replacement.begin(), replacement.end()); + } + // Append the content after the last match. If no replacements were made, the + // original string is left untouched. + if (num_replacements > 0) { + tmp.append(*s, pos, s->length() - pos); + s->swap(tmp); + } + return num_replacements; +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 4178ac9f..f2e1a944 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -57,6 +57,8 @@ namespace protobuf { // strings, so locale should not be taken into account. // ascii_isdigit() // Like above, but only accepts digits. +// ascii_isspace() +// Check if the character is a space character. // ---------------------------------------------------------------------- inline bool ascii_isalnum(char c) { @@ -69,6 +71,10 @@ inline bool ascii_isdigit(char c) { return ('0' <= c && c <= '9'); } +inline bool ascii_isspace(char c) { + return c == ' '; +} + // ---------------------------------------------------------------------- // HasPrefixString() // Check if a string begins with a given prefix. @@ -119,10 +125,15 @@ inline string StripSuffixString(const string& str, const string& suffix) { // in 'remove') with the character 'replacewith'. // Good for keeping html characters or protocol characters (\t) out // of places where they might cause a problem. +// StripWhitespace +// Removes whitespaces from both ends of the given string. // ---------------------------------------------------------------------- LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove, char replacewith); +LIBPROTOBUF_EXPORT void StripWhitespace(string* s); + + // ---------------------------------------------------------------------- // LowerString() // UpperString() @@ -501,6 +512,16 @@ inline string ToString(string a) { // StrCat() // These methods join some strings together. // ---------------------------------------------------------------------- +template +string StrCat( + const T1& a, const T2& b, const T3& c, const T4& d, const T5& e, + const T6& f, const T7& g) { + return internal::ToString(a) + internal::ToString(b) + + internal::ToString(c) + internal::ToString(d) + internal::ToString(e) + + internal::ToString(f) + internal::ToString(g); +} + template string StrCat( const T1& a, const T2& b, const T3& c, const T4& d, const T5& e) { @@ -556,6 +577,17 @@ string Join(const Range& components, // ---------------------------------------------------------------------- LIBPROTOBUF_EXPORT string ToHex(uint64 num); +// ---------------------------------------------------------------------- +// GlobalReplaceSubstring() +// Replaces all instances of a substring in a string. Does nothing +// if 'substring' is empty. Returns the number of replacements. +// +// NOTE: The string pieces must not overlap s. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT int GlobalReplaceSubstring(const string& substring, + const string& replacement, + string* s); + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h index e41f5e6f..f5365c38 100644 --- a/src/google/protobuf/stubs/type_traits.h +++ b/src/google/protobuf/stubs/type_traits.h @@ -35,6 +35,7 @@ // any changes here, make sure that you're not breaking any platforms. // // Define a small subset of tr1 type traits. The traits we define are: +// enable_if // is_integral // is_floating_point // is_pointer @@ -60,12 +61,27 @@ #include // For pair +#include #include // For true_type and false_type namespace google { namespace protobuf { namespace internal { +template +struct is_base_of { + typedef char (&yes)[1]; + typedef char (&no)[2]; + + static yes check(const B*); + static no check(const void*); + + enum { + value = sizeof(check(static_cast(NULL))) == sizeof(yes), + }; +}; + +template struct enable_if; template struct is_integral; template struct is_floating_point; template struct is_pointer; @@ -91,6 +107,13 @@ template struct is_same; template struct is_convertible; #endif +// enable_if, equivalent semantics to c++11 std::enable_if, specifically: +// "If B is true, the member typedef type shall equal T; otherwise, there +// shall be no member typedef type." +// Specified by 20.9.7.6 [Other transformations] + +template struct enable_if { typedef T type; }; +template struct enable_if {}; // is_integral is false except for the built-in integer types. A // cv-qualified type is integral if and only if the underlying type is. template struct is_integral : false_type { }; @@ -144,7 +167,7 @@ template struct is_pointer : is_pointer { }; #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) -namespace internal { +namespace type_traits_internal { template struct is_class_or_union { template static small_ tester(void (U::*)()); @@ -159,7 +182,7 @@ template struct is_enum_impl template struct is_enum_impl : false_type { }; -} // namespace internal +} // namespace type_traits_internal // Specified by TR1 [4.5.1] primary type categories. @@ -177,12 +200,12 @@ template struct is_enum_impl : false_type { }; // because it can't be used with some types (e.g. void or classes with // inaccessible conversion operators). template struct is_enum - : internal::is_enum_impl< + : type_traits_internal::is_enum_impl< is_same::value || is_integral::value || is_floating_point::value || is_reference::value || - internal::is_class_or_union::value, + type_traits_internal::is_class_or_union::value, T> { }; template struct is_enum : is_enum { }; @@ -300,7 +323,7 @@ template struct is_same : public true_type { }; // Specified by TR1 [4.6] Relationships between types #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) -namespace internal { +namespace type_traits_internal { // This class is an implementation detail for is_convertible, and you // don't need to know how it works to use is_convertible. For those @@ -317,14 +340,14 @@ struct ConvertHelper { static big_ Test(...); static From Create(); }; -} // namespace internal +} // namespace type_traits_internal // Inherits from true_type if From is convertible to To, false_type otherwise. template struct is_convertible : integral_constant::Test( - internal::ConvertHelper::Create())) + sizeof(type_traits_internal::ConvertHelper::Test( + type_traits_internal::ConvertHelper::Create())) == sizeof(small_)> { }; #endif diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 84cdbb57..fd04bef1 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1583,10 +1584,23 @@ void TextFormat::Printer::PrintFieldValue( } case FieldDescriptor::CPPTYPE_ENUM: { - const EnumValueDescriptor *enum_val = field->is_repeated() - ? reflection->GetRepeatedEnum(message, field, index) - : reflection->GetEnum(message, field); - generator.Print(printer->PrintEnum(enum_val->number(), enum_val->name())); + int enum_value = field->is_repeated() + ? reflection->GetRepeatedEnumValue(message, field, index) + : reflection->GetEnumValue(message, field); + const EnumValueDescriptor* enum_desc = + field->enum_type()->FindValueByNumber(enum_value); + if (enum_desc != NULL) { + generator.Print(printer->PrintEnum(enum_value, enum_desc->name())); + } else { + // Ordinarily, enum_desc should not be null, because proto2 has the + // invariant that set enum field values must be in-range, but with the + // new integer-based API for enums (or the RepeatedField loophole), + // it is possible for the user to force an unknown integer value. So we + // simply use the integer value itself as the enum value name in this + // case. + generator.Print(printer->PrintEnum(enum_value, + StringPrintf("%d", enum_value))); + } break; } diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 29549410..548962cb 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -40,6 +40,9 @@ #include #include +#ifndef _SHARED_PTR_H +#include +#endif #include #include diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index c48cc923..7450fe53 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -34,6 +34,7 @@ // // A proto file we will use for unit testing. +syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default @@ -429,7 +430,7 @@ message TestMutualRecursionB { } // Test that groups have disjoint field numbers from their siblings and -// parents. This is NOT possible in proto1; only proto2. When attempting +// parents. This is NOT possible in proto1; only google.protobuf. When attempting // to compile with proto1, this will emit an error; so we only include it // in protobuf_unittest_proto. message TestDupFieldNumber { // NO_PROTO1 @@ -505,6 +506,15 @@ message TestFieldOrderings { optional int64 my_int = 1; extensions 12 to 100; optional float my_float = 101; + message NestedMessage { + optional int64 oo = 2; + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + optional int32 bb = 1; + } + + optional NestedMessage optional_nested_message = 200; } diff --git a/src/google/protobuf/unittest_arena.proto b/src/google/protobuf/unittest_arena.proto new file mode 100644 index 00000000..6fdbbe02 --- /dev/null +++ b/src/google/protobuf/unittest_arena.proto @@ -0,0 +1,45 @@ +// 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. + +syntax = "proto2"; + +import "google/protobuf/unittest_no_arena_import.proto"; + +package proto2_arena_unittest; + + +message NestedMessage { + optional int32 d = 1; +} + +message ArenaMessage { + repeated NestedMessage repeated_nested_message = 1; + repeated ImportNoArenaNestedMessage repeated_import_no_arena_message = 2; +}; diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto index 0bb12e17..d4d6e869 100644 --- a/src/google/protobuf/unittest_custom_options.proto +++ b/src/google/protobuf/unittest_custom_options.proto @@ -32,8 +32,9 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // -// A proto file used to test the "custom options" feature of proto2. +// A proto file used to test the "custom options" feature of google.protobuf. +syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto new file mode 100644 index 00000000..66b31acf --- /dev/null +++ b/src/google/protobuf/unittest_drop_unknown_fields.proto @@ -0,0 +1,55 @@ +// 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. + +syntax = "proto3"; + +package unittest_drop_unknown_fields; + +message Foo { + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + } + optional int32 int32_value = 1; + optional NestedEnum enum_value = 2; +} + +message FooWithExtraFields { + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + QUX = 3; + } + optional int32 int32_value = 1; + optional NestedEnum enum_value = 2; + optional int32 extra_int32_value = 3; +} diff --git a/src/google/protobuf/unittest_embed_optimize_for.proto b/src/google/protobuf/unittest_embed_optimize_for.proto index ad515131..d8b0f9b9 100644 --- a/src/google/protobuf/unittest_embed_optimize_for.proto +++ b/src/google/protobuf/unittest_embed_optimize_for.proto @@ -34,6 +34,7 @@ // // A proto file which imports a proto file that uses optimize_for = CODE_SIZE. +syntax = "proto2"; import "google/protobuf/unittest_optimize_for.proto"; package protobuf_unittest; diff --git a/src/google/protobuf/unittest_empty.proto b/src/google/protobuf/unittest_empty.proto index b7337ef3..36443e7e 100644 --- a/src/google/protobuf/unittest_empty.proto +++ b/src/google/protobuf/unittest_empty.proto @@ -35,3 +35,4 @@ // This file intentionally left blank. (At one point this wouldn't compile // correctly.) +syntax = "proto2"; diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto index 3ba8b419..2250261d 100644 --- a/src/google/protobuf/unittest_enormous_descriptor.proto +++ b/src/google/protobuf/unittest_enormous_descriptor.proto @@ -35,6 +35,7 @@ // A proto file that has an extremely large descriptor. Used to test that // descriptors over 64k don't break the string literal length limit in Java. +syntax = "proto2"; package google.protobuf; option java_package = "com.google.protobuf"; diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto index 38275dc9..c1289e38 100644 --- a/src/google/protobuf/unittest_import.proto +++ b/src/google/protobuf/unittest_import.proto @@ -34,6 +34,7 @@ // // A proto file which is imported by unittest.proto to test importing. +syntax = "proto2"; // We don't put this in a package within proto2 because we need to make sure // that the generated code doesn't depend on being in the proto2 namespace. diff --git a/src/google/protobuf/unittest_import_lite.proto b/src/google/protobuf/unittest_import_lite.proto index 7cee113a..a7afa452 100644 --- a/src/google/protobuf/unittest_import_lite.proto +++ b/src/google/protobuf/unittest_import_lite.proto @@ -32,6 +32,7 @@ // // This is like unittest_import.proto but with optimize_for = LITE_RUNTIME. +syntax = "proto2"; package protobuf_unittest_import; option optimize_for = LITE_RUNTIME; diff --git a/src/google/protobuf/unittest_import_public.proto b/src/google/protobuf/unittest_import_public.proto index e5929cb5..ffaf7736 100644 --- a/src/google/protobuf/unittest_import_public.proto +++ b/src/google/protobuf/unittest_import_public.proto @@ -30,6 +30,7 @@ // Author: liujisi@google.com (Pherl Liu) +syntax = "proto2"; package protobuf_unittest_import; diff --git a/src/google/protobuf/unittest_import_public_lite.proto b/src/google/protobuf/unittest_import_public_lite.proto index e39bdb49..33549c22 100644 --- a/src/google/protobuf/unittest_import_public_lite.proto +++ b/src/google/protobuf/unittest_import_public_lite.proto @@ -30,6 +30,7 @@ // Author: liujisi@google.com (Pherl Liu) +syntax = "proto2"; package protobuf_unittest_import; diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto index 30dd67fb..662c0e46 100644 --- a/src/google/protobuf/unittest_lite.proto +++ b/src/google/protobuf/unittest_lite.proto @@ -32,6 +32,7 @@ // // This is like unittest.proto but with optimize_for = LITE_RUNTIME. +syntax = "proto2"; package protobuf_unittest; import "google/protobuf/unittest_import_lite.proto"; diff --git a/src/google/protobuf/unittest_lite_imports_nonlite.proto b/src/google/protobuf/unittest_lite_imports_nonlite.proto index 5ef8a06d..132d6a82 100644 --- a/src/google/protobuf/unittest_lite_imports_nonlite.proto +++ b/src/google/protobuf/unittest_lite_imports_nonlite.proto @@ -32,6 +32,7 @@ // // Tests that a "lite" message can import a regular message. +syntax = "proto2"; package protobuf_unittest; import "google/protobuf/unittest.proto"; diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto index 8fbe7abb..5a07ed12 100644 --- a/src/google/protobuf/unittest_mset.proto +++ b/src/google/protobuf/unittest_mset.proto @@ -34,6 +34,7 @@ // // This file contains messages for testing message_set_wire_format. +syntax = "proto2"; package protobuf_unittest; option optimize_for = SPEED; diff --git a/src/google/protobuf/unittest_no_arena.proto b/src/google/protobuf/unittest_no_arena.proto new file mode 100644 index 00000000..cd7cbbae --- /dev/null +++ b/src/google/protobuf/unittest_no_arena.proto @@ -0,0 +1,199 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This proto file contains copies of TestAllTypes and friends, but with arena +// support disabled in code generation. It allows us to test the performance +// impact against baseline (non-arena) google.protobuf. + +syntax = "proto2"; + +// Some generic_services option(s) added automatically. +// See: http://go/proto2-generic-services-default +option cc_generic_services = true; // auto-added +option java_generic_services = true; // auto-added +option py_generic_services = true; // auto-added + +import "google/protobuf/unittest_import.proto"; +import "google/protobuf/unittest_arena.proto"; + +// We don't put this in a package within proto2 because we need to make sure +// that the generated code doesn't depend on being in the proto2 namespace. +// In test_util.h we do "using namespace unittest = protobuf_unittest". +package protobuf_unittest_no_arena; + +// Protos optimized for SPEED use a strict superset of the generated code +// of equivalent ones optimized for CODE_SIZE, so we should optimize all our +// tests for speed unless explicitly testing code size optimization. +option optimize_for = SPEED; + +option java_outer_classname = "UnittestProto"; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + optional int32 bb = 1; + } + + enum NestedEnum { + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + + optional group OptionalGroup = 16 { + optional int32 a = 17; + } + + optional NestedMessage optional_nested_message = 18; + optional ForeignMessage optional_foreign_message = 19; + optional protobuf_unittest_import.ImportMessage optional_import_message = 20; + + optional NestedEnum optional_nested_enum = 21; + optional ForeignEnum optional_foreign_enum = 22; + optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + optional string optional_string_piece = 24 [ctype=STRING_PIECE]; + optional string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + optional protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + optional NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + repeated group RepeatedGroup = 46 { + optional int32 a = 47; + } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + // Singular with defaults + optional int32 default_int32 = 61 [default = 41 ]; + optional int64 default_int64 = 62 [default = 42 ]; + optional uint32 default_uint32 = 63 [default = 43 ]; + optional uint64 default_uint64 = 64 [default = 44 ]; + optional sint32 default_sint32 = 65 [default = -45 ]; + optional sint64 default_sint64 = 66 [default = 46 ]; + optional fixed32 default_fixed32 = 67 [default = 47 ]; + optional fixed64 default_fixed64 = 68 [default = 48 ]; + optional sfixed32 default_sfixed32 = 69 [default = 49 ]; + optional sfixed64 default_sfixed64 = 70 [default = -50 ]; + optional float default_float = 71 [default = 51.5 ]; + optional double default_double = 72 [default = 52e3 ]; + optional bool default_bool = 73 [default = true ]; + optional string default_string = 74 [default = "hello"]; + optional bytes default_bytes = 75 [default = "world"]; + + optional NestedEnum default_nested_enum = 81 [default = BAR ]; + optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR]; + optional protobuf_unittest_import.ImportEnum + default_import_enum = 83 [default = IMPORT_BAR]; + + optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"]; + optional string default_cord = 85 [ctype=CORD,default="123"]; + + // For oneof test + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + optional int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +message TestNoArenaMessage { + optional proto2_arena_unittest.ArenaMessage arena_message = 1; +}; diff --git a/src/google/protobuf/unittest_no_arena_import.proto b/src/google/protobuf/unittest_no_arena_import.proto new file mode 100644 index 00000000..072af49e --- /dev/null +++ b/src/google/protobuf/unittest_no_arena_import.proto @@ -0,0 +1,37 @@ +// 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. + +syntax = "proto2"; + +package proto2_arena_unittest; + +message ImportNoArenaNestedMessage { + optional int32 d = 1; +}; diff --git a/src/google/protobuf/unittest_no_field_presence.proto b/src/google/protobuf/unittest_no_field_presence.proto new file mode 100644 index 00000000..e04da0ac --- /dev/null +++ b/src/google/protobuf/unittest_no_field_presence.proto @@ -0,0 +1,138 @@ +// 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. + +// A proto file used to test a message type with no explicit field presence. + +syntax = "proto3"; + +// We want to test embedded proto2 messages, so include some proto2 types. +import "google/protobuf/unittest.proto"; + +package proto2_nofieldpresence_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + optional int32 bb = 1; + } + + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + } + + // Singular + // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make + // 'optional' optional. + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + + optional NestedMessage optional_nested_message = 18; + optional ForeignMessage optional_foreign_message = 19; + optional protobuf_unittest.TestAllTypes optional_proto2_message = 20; + + optional NestedEnum optional_nested_enum = 21; + optional ForeignEnum optional_foreign_enum = 22; + // N.B.: proto2-enum-type fields not allowed, because their default values + // might not be zero. + //optional protobuf_unittest.ForeignEnum optional_proto2_enum = 23; + + optional string optional_string_piece = 24 [ctype=STRING_PIECE]; + optional string optional_cord = 25 [ctype=CORD]; + + optional NestedMessage optional_lazy_message = 30 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest.TestAllTypes repeated_proto2_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + NestedEnum oneof_enum = 114; + } +} + +message TestProto2Required { + optional protobuf_unittest.TestRequired proto2 = 1; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + optional int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_FOO = 0; + FOREIGN_BAR = 1; + FOREIGN_BAZ = 2; +} diff --git a/src/google/protobuf/unittest_no_generic_services.proto b/src/google/protobuf/unittest_no_generic_services.proto index cf6d16c2..8fc7713c 100644 --- a/src/google/protobuf/unittest_no_generic_services.proto +++ b/src/google/protobuf/unittest_no_generic_services.proto @@ -30,6 +30,7 @@ // Author: kenton@google.com (Kenton Varda) +syntax = "proto2"; package google.protobuf.no_generic_services_test; diff --git a/src/google/protobuf/unittest_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto index 9f7b4eea..ee9cc7bd 100644 --- a/src/google/protobuf/unittest_optimize_for.proto +++ b/src/google/protobuf/unittest_optimize_for.proto @@ -34,6 +34,7 @@ // // A proto file which uses optimize_for = CODE_SIZE. +syntax = "proto2"; import "google/protobuf/unittest.proto"; package protobuf_unittest; diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto new file mode 100644 index 00000000..ba050d70 --- /dev/null +++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto @@ -0,0 +1,66 @@ +// 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. + +syntax = "proto3"; + +package proto2_preserve_unknown_enum_unittest; + +enum MyEnum { + FOO = 0; + BAR = 1; + BAZ = 2; +} + +enum MyEnumPlusExtra { + E_FOO = 0; + E_BAR = 1; + E_BAZ = 2; + E_EXTRA = 3; +} + +message MyMessage { + optional MyEnum e = 1; + repeated MyEnum repeated_e = 2; + repeated MyEnum repeated_packed_e = 3 [packed=true]; + oneof o { + MyEnum oneof_e_1 = 4; + MyEnum oneof_e_2 = 5; + } +} + +message MyMessagePlusExtra { + optional MyEnumPlusExtra e = 1; + repeated MyEnumPlusExtra repeated_e = 2; + repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true]; + oneof o { + MyEnumPlusExtra oneof_e_1 = 4; + MyEnumPlusExtra oneof_e_2 = 5; + } +} diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto new file mode 100644 index 00000000..84ec7960 --- /dev/null +++ b/src/google/protobuf/unittest_proto3_arena.proto @@ -0,0 +1,143 @@ +// 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. + +syntax = "proto3"; + + +import "google/protobuf/unittest_import.proto"; + +package proto3_arena_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + optional int32 bb = 1; + } + + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + NEG = -1; // Intentionally negative. + } + + // Singular + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + + optional group OptionalGroup = 16 { + optional int32 a = 17; + } + + optional NestedMessage optional_nested_message = 18; + optional ForeignMessage optional_foreign_message = 19; + optional protobuf_unittest_import.ImportMessage optional_import_message = 20; + + optional NestedEnum optional_nested_enum = 21; + optional ForeignEnum optional_foreign_enum = 22; + + optional string optional_string_piece = 24 [ctype=STRING_PIECE]; + optional string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + optional protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + optional NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + repeated group RepeatedGroup = 46 { + optional int32 a = 47; + } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + optional int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_FOO = 0; + FOREIGN_BAR = 1; + FOREIGN_BAZ = 2; +} diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h new file mode 100644 index 00000000..fb5380aa --- /dev/null +++ b/src/google/protobuf/unknown_enum_impl.h @@ -0,0 +1,132 @@ +// 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_UTIL_UNKNOWN_ENUM_IMPL_H__ +#define GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__ + +#include + +#include +#include "net/proto/tagmapper.h" +#include + +namespace google { +namespace protobuf { + +// google/protobuf/message.h +class Message; + +namespace util { + +// NOTE: You should not call these functions directly. Instead use either +// HAS_UNKNOWN_ENUM() or GET_UNKNOWN_ENUM(), defined in the public header. +// The macro-versions operate in a type-safe manner and behave appropriately +// for the proto version of the message, whereas these versions assume a +// specific proto version and allow the caller to pass in any arbitrary integer +// value as a field number. +// +// Returns whether the message has unrecognized the enum value for a given +// field. It also stores the value into the unknown_value parameter if the +// function returns true and the pointer is not NULL. +// +// In proto2, invalid enum values will be treated as unknown fields. This +// function checks that case. +bool HasUnknownEnum(const Message& message, int32 field_number, + int32* unknown_value = nullptr); +// Same as above, but returns all unknown enums. +bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number, + vector* unknown_values = nullptr); +// In proto1, invalue enum values are stored in the same way as valid enum +// values. +// TODO(karner): Delete this once the migration to proto2 is complete. +bool HasUnknownEnumProto1(const Message& message, int32 field_number, + int32* unknown_value); +// Same as above, but returns all unknown enums. +bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number, + vector* unknown_values); +// Invokes the appropriate version based on whether the message is proto1 +// or proto2. +template +bool HasUnknownEnum_Template(const T& message, int32 field_number, + int32* unknown_value = nullptr) { + if (internal::is_base_of::value || + !internal::is_base_of::value) { + return HasUnknownEnum(message, field_number, unknown_value); + } else { + return HasUnknownEnumProto1(message, field_number, unknown_value); + } +} +// Invokes the appropriate version based on whether the message is proto1 +// or proto2. +template +bool GetRepeatedEnumUnknowns_Template( + const T& message, int32 field_number, + vector* unknown_values = nullptr) { + if (internal::is_base_of::value || + !internal::is_base_of::value) { + return GetRepeatedEnumUnknowns(message, field_number, unknown_values); + } else { + return GetRepeatedEnumUnknownsProto1(message, field_number, + unknown_values); + } +} + +// NOTE: You should not call these functions directly. Instead use +// SET_UNKNOWN_ENUM(), defined in the public header. The macro-versions +// operate in a type-safe manner and behave appropriately for the proto +// version of the message, whereas these versions assume a specific proto +// version and allow the caller to pass in any arbitrary integer value as a +// field number. +// +// Sets the given value in the unknown fields of the message. +void SetUnknownEnum(Message* message, int32 field_number, int32 unknown_value); +// In proto1, invalue enum values are stored in the same way as valid enum +// values. +// TODO(karner): Delete this once the migration to proto2 is complete. +void SetUnknownEnumProto1(Message* message, int32 field_number, + int32 unknown_value); +// Invokes the appropriate version based on whether the message is proto1 +// or proto2. +template +void SetUnknownEnum_Template(T* message, int32 field_number, + int32 unknown_value) { + if (internal::is_base_of::value || + !internal::is_base_of::value) { + SetUnknownEnum(message, field_number, unknown_value); + } else { + SetUnknownEnumProto1(message, field_number, unknown_value); + } +} + +} // namespace util +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__ diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto new file mode 100644 index 00000000..caafadcd --- /dev/null +++ b/src/google/protobuf/unknown_enum_test.proto @@ -0,0 +1,61 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Definitions of protos for testing cross-version compatibility. The +// UpRevision message acts as if it were a newer version of the DownRevision +// message. That is, UpRevision shares all the same fields as DownRevision, +// but UpRevision can add fields and add enum values. +syntax = "proto2"; + +package google.protobuf.util; + + +message DownRevision { + enum Enum { + DEFAULT_VALUE = 2; + NONDEFAULT_VALUE = 3; + } + + optional Enum value = 1 [default = DEFAULT_VALUE]; + repeated Enum values = 2; +} + +message UpRevision { + enum Enum { + DEFAULT_VALUE = 2; + NONDEFAULT_VALUE = 3; + NEW_VALUE = 4; + NEW_VALUE_2 = 5; + NEW_VALUE_3 = 6; + } + + optional Enum value = 1 [default = DEFAULT_VALUE]; + repeated Enum values = 2; +} diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 020a323b..e15280c8 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -44,6 +44,25 @@ namespace google { namespace protobuf { +namespace { +// This global instance is returned by unknown_fields() on any message class +// when the object has no unknown fields. This is necessary because we now +// instantiate the UnknownFieldSet dynamically only when required. +UnknownFieldSet* default_unknown_field_set_instance_ = NULL; + +void InitDefaultUnknownFieldSet() { + default_unknown_field_set_instance_ = new UnknownFieldSet(); +} + +GOOGLE_PROTOBUF_DECLARE_ONCE(default_unknown_field_set_once_init_); +} + +const UnknownFieldSet* UnknownFieldSet::default_instance() { + ::google::protobuf::GoogleOnceInit(&default_unknown_field_set_once_init_, + &InitDefaultUnknownFieldSet); + return default_unknown_field_set_instance_; +} + UnknownFieldSet::UnknownFieldSet() : fields_(NULL) {} @@ -53,31 +72,63 @@ UnknownFieldSet::~UnknownFieldSet() { } void UnknownFieldSet::ClearFallback() { - GOOGLE_DCHECK(fields_ != NULL); - for (int i = 0; i < fields_->size(); i++) { - (*fields_)[i].Delete(); + if (fields_ != NULL) { + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); + } + delete fields_; + fields_ = NULL; } - fields_->clear(); } void UnknownFieldSet::ClearAndFreeMemory() { if (fields_ != NULL) { Clear(); - delete fields_; - fields_ = NULL; + } +} + +void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) { + int other_field_count = other.field_count(); + if (other_field_count > 0) { + fields_ = new vector(); + for (int i = 0; i < other_field_count; i++) { + fields_->push_back((*other.fields_)[i]); + fields_->back().DeepCopy(); + } } } void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { - for (int i = 0; i < other.field_count(); i++) { - AddField(other.field(i)); + int other_field_count = other.field_count(); + if (other_field_count > 0) { + if (fields_ == NULL) fields_ = new vector(); + for (int i = 0; i < other_field_count; i++) { + fields_->push_back((*other.fields_)[i]); + fields_->back().DeepCopy(); + } } } +// A specialized MergeFrom for performance when we are merging from an UFS that +// is temporary and can be destroyed in the process. +void UnknownFieldSet::MergeFromAndDestroy(UnknownFieldSet* other) { + int other_field_count = other->field_count(); + if (other_field_count > 0) { + if (fields_ == NULL) fields_ = new vector(); + for (int i = 0; i < other_field_count; i++) { + fields_->push_back((*other->fields_)[i]); + (*other->fields_)[i].Reset(); + } + } + delete other->fields_; + other->fields_ = NULL; +} + int UnknownFieldSet::SpaceUsedExcludingSelf() const { if (fields_ == NULL) return 0; int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size(); + for (int i = 0; i < fields_->size(); i++) { const UnknownField& field = (*fields_)[i]; switch (field.type()) { @@ -101,61 +152,60 @@ int UnknownFieldSet::SpaceUsed() const { } void UnknownFieldSet::AddVarint(int number, uint64 value) { - if (fields_ == NULL) fields_ = new vector; UnknownField field; field.number_ = number; field.SetType(UnknownField::TYPE_VARINT); field.varint_ = value; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); } void UnknownFieldSet::AddFixed32(int number, uint32 value) { - if (fields_ == NULL) fields_ = new vector; UnknownField field; field.number_ = number; field.SetType(UnknownField::TYPE_FIXED32); field.fixed32_ = value; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); } void UnknownFieldSet::AddFixed64(int number, uint64 value) { - if (fields_ == NULL) fields_ = new vector; UnknownField field; field.number_ = number; field.SetType(UnknownField::TYPE_FIXED64); field.fixed64_ = value; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); } string* UnknownFieldSet::AddLengthDelimited(int number) { - if (fields_ == NULL) fields_ = new vector; UnknownField field; field.number_ = number; field.SetType(UnknownField::TYPE_LENGTH_DELIMITED); field.length_delimited_.string_value_ = new string; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); return field.length_delimited_.string_value_; } UnknownFieldSet* UnknownFieldSet::AddGroup(int number) { - if (fields_ == NULL) fields_ = new vector; UnknownField field; field.number_ = number; field.SetType(UnknownField::TYPE_GROUP); field.group_ = new UnknownFieldSet; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); return field.group_; } void UnknownFieldSet::AddField(const UnknownField& field) { - if (fields_ == NULL) fields_ = new vector; + if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); fields_->back().DeepCopy(); } void UnknownFieldSet::DeleteSubrange(int start, int num) { - GOOGLE_DCHECK(fields_ != NULL); // Delete the specified fields. for (int i = 0; i < num; ++i) { (*fields_)[i + start].Delete(); @@ -168,6 +218,11 @@ void UnknownFieldSet::DeleteSubrange(int start, int num) { for (int i = 0; i < num; ++i) { fields_->pop_back(); } + if (fields_ && fields_->size() == 0) { + // maintain invariant: never hold fields_ if empty. + delete fields_; + fields_ = NULL; + } } void UnknownFieldSet::DeleteByNumber(int number) { @@ -185,13 +240,18 @@ void UnknownFieldSet::DeleteByNumber(int number) { } } fields_->resize(left); + if (left == 0) { + // maintain invariant: never hold fields_ if empty. + delete fields_; + fields_ = NULL; + } } bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) { UnknownFieldSet other; if (internal::WireFormat::SkipMessage(input, &other) && input->ConsumedEntireMessage()) { - MergeFrom(other); + MergeFromAndDestroy(&other); return true; } else { return false; @@ -227,6 +287,22 @@ void UnknownField::Delete() { } } +// Reset all owned ptrs, a special function for performance, to avoid double +// owning the ptrs, when we merge from a temporary UnknownFieldSet objects. +void UnknownField::Reset() { + switch (type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + length_delimited_.string_value_ = NULL; + break; + case UnknownField::TYPE_GROUP: { + group_ = NULL; + break; + } + default: + break; + } +} + void UnknownField::DeepCopy() { switch (type()) { case UnknownField::TYPE_LENGTH_DELIMITED: @@ -234,8 +310,8 @@ void UnknownField::DeepCopy() { *length_delimited_.string_value_); break; case UnknownField::TYPE_GROUP: { - UnknownFieldSet* group = new UnknownFieldSet; - group->MergeFrom(*group_); + UnknownFieldSet* group = new UnknownFieldSet(); + group->InternalMergeFrom(*group_); group_ = group; break; } diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 31f17e2a..6f7a9fdb 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -88,6 +88,9 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // Merge the contents of some other UnknownFieldSet with this one. void MergeFrom(const UnknownFieldSet& other); + // Similar to above, but this function will destroy the contents of other. + void MergeFromAndDestroy(UnknownFieldSet* other); + // Swaps the contents of some other UnknownFieldSet with this one. inline void Swap(UnknownFieldSet* x); @@ -141,12 +144,22 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { return ParseFromArray(data.data(), static_cast(data.size())); } + static const UnknownFieldSet* default_instance(); private: - + // For InternalMergeFrom + friend class UnknownField; + // Merges from other UnknownFieldSet. This method assumes, that this object + // is newly created and has fields_ == NULL; + void InternalMergeFrom(const UnknownFieldSet& other); void ClearFallback(); + // fields_ is either NULL, or a pointer to a vector that is *non-empty*. We + // never hold the empty vector because we want the 'do we have any unknown + // fields' check to be fast, and avoid a cache miss: the UFS instance gets + // embedded in the message object, so 'fields_ != NULL' tests a member + // variable hot in the cache, without the need to go touch a vector somewhere + // else in memory. std::vector* fields_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); }; @@ -198,6 +211,10 @@ class LIBPROTOBUF_EXPORT UnknownField { // If this UnknownField contains a pointer, delete it. void Delete(); + // Reset all the underlying pointers to NULL. A special function to be only + // used while merging from a temporary UFS. + void Reset(); + // Make a deep copy of any pointers in this UnknownField. void DeepCopy(); @@ -222,13 +239,14 @@ class LIBPROTOBUF_EXPORT UnknownField { // inline implementations inline void UnknownFieldSet::Clear() { - if (fields_ != NULL) { + if (fields_) { ClearFallback(); } } inline bool UnknownFieldSet::empty() const { - return fields_ == NULL || fields_->empty(); + // Invariant: fields_ is never empty if present. + return !fields_; } inline void UnknownFieldSet::Swap(UnknownFieldSet* x) { @@ -236,9 +254,10 @@ inline void UnknownFieldSet::Swap(UnknownFieldSet* x) { } inline int UnknownFieldSet::field_count() const { - return (fields_ == NULL) ? 0 : static_cast(fields_->size()); + return fields_ ? static_cast(fields_->size()) : 0; } inline const UnknownField& UnknownFieldSet::field(int index) const { + GOOGLE_DCHECK(fields_ != NULL); return (*fields_)[index]; } inline UnknownField* UnknownFieldSet::mutable_field(int index) { diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index aaaa2e89..6bba8fc7 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -482,6 +482,13 @@ TEST_F(UnknownFieldSetTest, UnknownEnumValue) { } } +TEST_F(UnknownFieldSetTest, SpaceUsedExcludingSelf) { + UnknownFieldSet empty; + empty.AddVarint(1, 0); + EXPECT_EQ(/* vector */ 24 + /* sizeof(UnknownField) */ 16, + empty.SpaceUsedExcludingSelf()); +} + TEST_F(UnknownFieldSetTest, SpaceUsed) { unittest::TestEmptyMessage empty_message; diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 6bdfcd62..f4f02157 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -512,10 +512,15 @@ bool WireFormat::ParseAndMergeField( int value; if (!WireFormatLite::ReadPrimitive( input, &value)) return false; - const EnumValueDescriptor* enum_value = - field->enum_type()->FindValueByNumber(value); - if (enum_value != NULL) { - message_reflection->AddEnum(message, field, enum_value); + if (message->GetDescriptor()->file()->syntax() == + FileDescriptor::SYNTAX_PROTO3) { + message_reflection->AddEnumValue(message, field, value); + } else { + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + message_reflection->AddEnum(message, field, enum_value); + } } } @@ -572,21 +577,31 @@ bool WireFormat::ParseAndMergeField( int value; if (!WireFormatLite::ReadPrimitive( input, &value)) return false; - const EnumValueDescriptor* enum_value = - field->enum_type()->FindValueByNumber(value); - if (enum_value != NULL) { + if (message->GetDescriptor()->file()->syntax() == + FileDescriptor::SYNTAX_PROTO3) { if (field->is_repeated()) { - message_reflection->AddEnum(message, field, enum_value); + message_reflection->AddEnumValue(message, field, value); } else { - message_reflection->SetEnum(message, field, enum_value); + message_reflection->SetEnumValue(message, field, value); } } else { - // The enum value is not one of the known values. Add it to the - // UnknownFieldSet. - int64 sign_extended_value = static_cast(value); - message_reflection->MutableUnknownFields(message) - ->AddVarint(WireFormatLite::GetTagFieldNumber(tag), - sign_extended_value); + const EnumValueDescriptor* enum_value = + field->enum_type()->FindValueByNumber(value); + if (enum_value != NULL) { + if (field->is_repeated()) { + message_reflection->AddEnum(message, field, enum_value); + } else { + message_reflection->SetEnum(message, field, enum_value); + } + } else { + // The enum value is not one of the known values. Add it to the + // UnknownFieldSet. + int64 sign_extended_value = static_cast(value); + message_reflection->MutableUnknownFields(message) + ->AddVarint( + WireFormatLite::GetTagFieldNumber(tag), + sign_extended_value); + } } break; } diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 8de82784..c80a7050 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -291,7 +291,7 @@ bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input, int, WireFormatLite::TYPE_ENUM>(input, &value)) { return false; } - if (is_valid(value)) { + if (is_valid == NULL || is_valid(value)) { values->Add(value); } } @@ -451,19 +451,24 @@ void WireFormatLite::WriteMessageMaybeToArray(int field_number, } } -bool WireFormatLite::ReadString(io::CodedInputStream* input, - string* value) { - // String is for UTF-8 text only +static inline bool ReadBytesToString(io::CodedInputStream* input, + string* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +static inline bool ReadBytesToString(io::CodedInputStream* input, + string* value) { uint32 length; - if (!input->ReadVarint32(&length)) return false; - if (!input->InternalReadStringInline(value, length)) return false; - return true; + return input->ReadVarint32(&length) && + input->InternalReadStringInline(value, length); } -bool WireFormatLite::ReadBytes(io::CodedInputStream* input, - string* value) { - uint32 length; - if (!input->ReadVarint32(&length)) return false; - return input->InternalReadStringInline(value, length); + +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string* value) { + return ReadBytesToString(input, value); +} + +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string** p) { + if (*p == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + *p = new ::std::string(); + } + return ReadBytesToString(input, *p); } } // namespace internal diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index 21aa4889..acf88ead 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -292,13 +292,22 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static bool ReadPackedPrimitiveNoInline(input, RepeatedField* value); // Read a packed enum field. Values for which is_valid() returns false are - // dropped. + // dropped. If is_valid == NULL, no values are dropped. static bool ReadPackedEnumNoInline(input, bool (*is_valid)(int), RepeatedField* value); - static bool ReadString(input, string* value); - static bool ReadBytes (input, string* value); + // Read a string. ReadString(..., string* value) requires an existing string. + static inline bool ReadString(input, string* value); + // ReadString(..., string** p) is internal-only, and should only be called + // from generated code. It starts by setting *p to "new string" + // if *p == &GetEmptyStringAlreadyInited(). It then invokes + // ReadString(input, *p). This is useful for reducing code size. + static inline bool ReadString(input, string** p); + // Analogous to ReadString(). + static bool ReadBytes(input, string* value); + static bool ReadBytes(input, string** p); + static inline bool ReadGroup (field_number, input, MessageLite* value); static inline bool ReadMessage(input, MessageLite* value); @@ -654,6 +663,19 @@ inline int64 WireFormatLite::ZigZagDecode64(uint64 n) { return (n >> 1) ^ -static_cast(n & 1); } +// String is for UTF-8 text only, but, even so, ReadString() can simply +// call ReadBytes(). + +inline bool WireFormatLite::ReadString(io::CodedInputStream* input, + string* value) { + return ReadBytes(input, value); +} + +inline bool WireFormatLite::ReadString(io::CodedInputStream* input, + string** p) { + return ReadBytes(input, p); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index feb22540..129fc63f 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -47,6 +47,7 @@ #include #include #include +#include namespace google { @@ -426,6 +427,7 @@ bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, } + inline bool WireFormatLite::ReadGroup(int field_number, io::CodedInputStream* input, MessageLite* value) { @@ -442,15 +444,12 @@ inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input, MessageLite* value) { uint32 length; if (!input->ReadVarint32(&length)) return false; - if (!input->IncrementRecursionDepth()) return false; - io::CodedInputStream::Limit limit = input->PushLimit(length); - if (!value->MergePartialFromCodedStream(input)) return false; + std::pair p = + input->IncrementRecursionDepthAndPushLimit(length); + if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false; // Make sure that parsing stopped when the limit was hit, not at an endgroup // tag. - if (!input->ConsumedEntireMessage()) return false; - input->PopLimit(limit); - input->DecrementRecursionDepth(); - return true; + return input->DecrementRecursionDepthAndPopLimit(p.first); } // We name the template parameter something long and extremely unlikely to occur @@ -483,17 +482,14 @@ inline bool WireFormatLite::ReadMessageNoVirtual( io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) { uint32 length; if (!input->ReadVarint32(&length)) return false; - if (!input->IncrementRecursionDepth()) return false; - io::CodedInputStream::Limit limit = input->PushLimit(length); - if (!value-> + std::pair p = + input->IncrementRecursionDepthAndPushLimit(length); + if (p.second < 0 || !value-> MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) return false; // Make sure that parsing stopped when the limit was hit, not at an endgroup // tag. - if (!input->ConsumedEntireMessage()) return false; - input->PopLimit(limit); - input->DecrementRecursionDepth(); - return true; + return input->DecrementRecursionDepthAndPopLimit(p.first); } // =================================================================== diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 81a024b3..a3062a6a 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -980,7 +980,8 @@ TEST_F(Utf8ValidationTest, WriteInvalidUTF8String) { #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED ASSERT_EQ(1, errors.size()); EXPECT_TRUE(StartsWith(errors[0], - "String field 'data' contains invalid UTF-8 data when " + "String field 'protobuf_unittest.OneString.data' " + "contains invalid UTF-8 data when " "serializing a protocol buffer. Use the " "'bytes' type if you intend to send raw bytes.")); #else @@ -1003,7 +1004,8 @@ TEST_F(Utf8ValidationTest, ReadInvalidUTF8String) { #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED ASSERT_EQ(1, errors.size()); EXPECT_TRUE(StartsWith(errors[0], - "String field 'data' contains invalid UTF-8 data when " + "String field 'protobuf_unittest.OneString.data' " + "contains invalid UTF-8 data when " "parsing a protocol buffer. Use the " "'bytes' type if you intend to send raw bytes.")); -- cgit v1.2.3